【C】——APUE小程序之递归遍历目录

时间:2021-03-03 12:17:46

  递归降序遍历目录层次结构,并按文件类型计数。

  先介绍相关的函数:

#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 }

  虽然是个空目录但是给的结果却是

.

..

  因此要忽略掉这两个,否则会进入死循环;