【C】——APUE小程序之递归遍历目录
递归降序遍历目录层次结构,并按文件类型计数。
先介绍相关的函数:
#include<dirent.h> DIR *opendir(const char *pathname); //打开目录 返回值:成功返回指针,出错返回NULL struct dirent *readdir(DIR *dp); //读取目录 返回值:成功返回指针,出错返回NULL void rewinddir(DIR *dp); //重设读取目录的位置为开头位置 int closedir(DIR *dp); //关闭目录 返回值:成功返回0,出错返回-1 long telldir(DIR *dp); //取得目录流的读取位置 返回值:与dp关联的目录中的当前位置 void seekdir(DIR *dp, long loc); //设置下回读取目录的位置 struct dirent{ ino_t d_ino; //i-node number char d_name[NAME_MAX + 1]; //null-terminated filename }
改写APUE的代码:
1 #include<stdio.h> 2 #include<dirent.h> 3 #include<sys/stat.h> 4 #include<string.h> 5 #include<stdlib.h> 6 7 static int nreg = 0, ndir = 0, nblk = 0, nchr = 0, nfifo = 0, nslink = 0, nsock = 0, ntot = 0; 8 9 static char *fullpath; 10 11 int myfunc(const char *pathname, const struct stat *statptr, int type) 12 { 13 switch(type){ 14 case 1: 15 switch(statptr->st_mode & S_IFMT){ 16 case S_IFREG: nreg++; break; 17 case S_IFBLK: nblk++; break; 18 case S_IFCHR: nchr++; break; 19 case S_IFIFO: nfifo++; break; 20 case S_IFLNK: nslink++; break; 21 case S_IFSOCK: nsock++; break; 22 case S_IFDIR:{ 23 printf("for S_IFDIR for %s\n",pathname); 24 } 25 } 26 break; 27 case 2: //文件夹 28 ndir++; break; 29 case 3: 30 printf("cant read directory %s\n",pathname); 31 case 4: 32 printf("stat error for %s\n",pathname); 33 } 34 35 return 0; 36 } 37 38 int dopath() 39 { 40 struct stat statbuf; //文件信息 41 struct dirent *dirp; //文件夹信息,包括i-node number filename 42 DIR *dp; //打开目录返回的指针 43 char *ptr; 44 45 if((lstat(fullpath,&statbuf)) < 0) 46 return(myfunc(fullpath,&statbuf,4)); 47 if(S_ISDIR(statbuf.st_mode) == 0) //判断是否是文件夹 48 return(myfunc(fullpath,&statbuf,1)); 49 50 myfunc(fullpath,&statbuf,2); //是目录则调用函数使目录数量自加一 51 52 ptr = fullpath + strlen(fullpath); 53 *ptr++ = '/'; 54 *ptr = 0; 55 56 if((dp = opendir(fullpath)) == NULL) 57 return(myfunc(fullpath,&statbuf,3)); 58 59 while((dirp = readdir(dp)) != NULL){ 60 if(strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0) 61 continue; 62 strcpy(ptr, dirp->d_name); 63 64 dopath(); 65 } 66 67 closedir(dp); 68 69 } 70 71 void ftw(char *pathname) 72 { 73 #ifdef PATH_MAX 74 const int PATH_LEN = PATH_MAX; 75 #else 76 const int PATH_LEN = 1024; 77 #endif 78 79 fullpath = malloc(PATH_LEN); 80 81 strncpy(fullpath,pathname,PATH_LEN); 82 83 fullpath[PATH_LEN - 1] = '\0'; 84 85 dopath(); 86 } 87 88 int main(int argc, char *argv[]) 89 { 90 if(argc != 2){ 91 printf("enter two args\n"); 92 exit(1); 93 } 94 95 ftw(argv[1]); 96 97 printf("regular files: }\n",nreg); 98 printf("directories : }\n",ndir); 99 printf("block special: }\n",nblk); 100 printf("char special: }\n",nchr); 101 printf("FIFOS: }\n",nfifo); 102 printf("symboli links: }\n",nslink); 103 printf("sockets: }\n",nsock); 104 105 }
需要注意的是第60行的判断一定不能少,因为在linux下创建一个空目录的时候,用ls查看其属性发现里面大小是2.写一个程序看下一个空目录里都有神马?
1 #include<stdio.h> 2 #include<dirent.h> 3 #include<stdlib.h> 4 #include<string.h> 5 6 int main(int argc, char *argv[]) 7 { 8 DIR *dp; 9 struct dirent *dirp; 10 char pathname[20]; 11 12 if(argc != 2){ 13 printf("please enter to args\n"); 14 exit(1); 15 } 16 17 puts(argv[1]); 18 19 strncpy(pathname, argv[1], 20); 20 21 if((dp = opendir(pathname)) == NULL){ 22 printf("opendir %s error\n",argv[1]); 23 exit(2); 24 } 25 26 while((dirp = readdir(dp)) != NULL){ 27 printf("%s\n",dirp->d_name); 28 } 29 30 closedir(dp); 31 32 return 0; 33 }
虽然是个空目录但是给的结果却是
.
..
因此要忽略掉这两个,否则会进入死循环;