用C语言实现统计一个文件夹中各种文件的比例

  《UNIX环境高级编程》中的程序清单4-7就介绍了如何实现递归地统计某个目录下面的文件!我刚开始看过它的代码后,觉得照着敲太没意思了,所以就合上书自己写了一遍!为此还写了一篇博文,这是博文地址: 在linux下用C语言实现递归查看某个目录中的所有文件【CSDN】!

  今天做《Unix环境高级编程》的课后题,看到题目4.11这里提供了一种新的实现这个程序的思路,那就是每回读到一个目录,就通过chdir函数进入到这个目录,然后再通过opendir函数和readdir函数来读取这个目录中的文件,然后一个一个分析,如果是目录,则进行递归调用。如果不是目录,则对这个文件进行计数后立刻返回!这样一个一个分析完目录中的所有文件之后再来进行一个chdir(".."),返回到上一级的目录。具体的实现代码如下:

  

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<errno.h>
  5 #include<linux/limits.h>
  6 #include<unistd.h>
  7 #include<sys/types.h>
  8 #include<sys/stat.h>
  9 #include<dirent.h>
 10 
 11 //所有函数的声明
 12 typedef int MyFunc(const char *,const struct stat*,int);
 13 static MyFunc myfunc;        //定义处理文件的函数
 14 static int myftw(const char *,MyFunc *);
 15 static int dopath(MyFunc *);
 16 
 17 //定义的全局变量
 18 static char *fullpath;    //存放文件的名称的变量
 19 static long sock_c,lnk_c,reg_c,blk_c,dir_c,chr_c,fifo_c,total_c;    //统计各种文件类型的数量
 20 
 21 //myfunc函数中需要定义的宏
 22 #define FTW_F 1        //文件类型是文件
 23 #define FTW_D 2        //文件类型是目录
 24 #define FTW_NS 3    //一个文件不能stat
 25 #define FTW_ND 4    //一个目录不能被读
 26 int main(int argc,char *argv[])
 27 {
 28     if(argc != 2)
 29     {
 30     printf("Usage:%s pathname
",argv[0]+2);
 31     exit(EXIT_FAILURE);
 32     }
 33     myftw(argv[1],myfunc);
 34     total_c = sock_c+lnk_c+reg_c+blk_c+dir_c+chr_c+fifo_c;
 35     if(0 == total_c)
 36     {
 37     total_c = 1;
 38     }
 39     printf("socket files    = %7ld, %5.2f%%
",sock_c,sock_c*100.0/total_c);
 40     printf("link files      = %7ld, %5.2f%%
",lnk_c,lnk_c*100.0/total_c);
 41     printf("regular files   = %7ld, %5.2f%%
",reg_c,reg_c*100.0/total_c);
 42     printf("block files     = %7ld, %5.2f%%
",blk_c,blk_c*100.0/total_c);
 43     printf("directory files = %7ld, %5.2f%%
",dir_c,dir_c*100.0/total_c);
 44     printf("character files = %7ld, %5.2f%%
",chr_c,chr_c*100.0/total_c);
 45     printf("FIFO files      = %7ld, %5.2f%%
",fifo_c,fifo_c*100.0/total_c);
 46     printf("total files     = %7ld, %5.2f%%
",total_c,total_c*100.0/total_c);
 47 
 48     return 0;
 49 }
 50 static int myftw(const char* pathname,MyFunc *pmyfunc)
 51 {
 52     int ret;
 53 
 54     fullpath = (char *)malloc(sizeof(char)*PATH_MAX);
 55     strcpy(fullpath,pathname);
 56     ret = dopath(myfunc);
 57     free(fullpath);
 58 
 59     return ret;
 60 }
 61 static int dopath(MyFunc *pmyfunc)
 62 {
 63     int ret;
 64     struct stat statbuf;
 65     char *ptr;
 66     DIR *dp;
 67     struct dirent* dirp;
 68 
 69     if(-1 == lstat(fullpath,&statbuf))
 70     {
 71     ret = pmyfunc(fullpath,&statbuf,FTW_NS);
 72     return ret;
 73     }
 74     if(S_ISDIR(statbuf.st_mode) != 1)
 75     {
 76     ret = pmyfunc(fullpath,&statbuf,FTW_F);
 77     return ret;
 78     }
 79 
 80     //使目录文件++
 81     if(0 != (ret=pmyfunc(fullpath,&statbuf,FTW_D)))
 82     return ret;
 83 
 84     //如果是目录文件则进入这个目录
 85     if(-1 == chdir(fullpath))
 86     {
 87     printf("%s[chdir]%s
",fullpath,strerror(errno));
 88     ret == -1;
 89     return ret;
 90     }
 91 
 92     //打开当前目录
 93     if(NULL == (dp=opendir(".")))
 94     {
 95     ret = pmyfunc(fullpath,&statbuf,FTW_ND);
 96     return ret;
 97     }
 98     while(NULL != (dirp=readdir(dp)))
 99     {
100     //忽略.和..文件(dot)
101     if(0==strcmp(dirp->d_name,".") || 0==strcmp(dirp->d_name,".."))
102         continue;
103     memset(fullpath,0,PATH_MAX);
104     strcpy(fullpath,dirp->d_name);
105 
106     if(0 != (ret=dopath(myfunc)))    //进行递归
107         break;
108     }
109     chdir("..");    //将当前目录设置为上一级目录
110     //对关闭文件进行判断
111     if(-1 == closedir(dp))
112     {
113     printf("不能关闭%s
Error:%s",fullpath,strerror(errno));
114     }
115 
116     return ret;
117 }
118 static int myfunc(const char * pathname,const struct stat * statptr,int type)
119 {
120     switch(type)
121     {
122     case FTW_F:
123     switch(statptr->st_mode & S_IFMT)
124     {
125     case S_IFSOCK:    sock_c++;    break;
126     case S_IFLNK:    lnk_c++;    break;
127     case S_IFREG:    reg_c++;    break;
128     case S_IFBLK:    blk_c++;    break;
129     case S_IFCHR:    chr_c++;    break;
130     case S_IFIFO:    fifo_c++;    break;
131     case S_IFDIR:
132         printf("Error:这里不应该出现目录文件%s!

Error:%s
",pathname,strerror(errno));
133         break;
134     }
135     break;
136     case FTW_D:
137     dir_c++;    break;
138     case FTW_ND:
139     printf("不能打开目录%s
Error:%s
",pathname,strerror(errno));
140     break;
141     case FTW_NS:
142     printf("不能打开文件%s
Error:%s
",pathname,strerror(errno));
143     break;
144     }
145     return 0;
146 }

  我这个代码并不是我自己合上书写的,而是在W.Richard Stevens书中给出的代码的基础上改的!在此要特别感谢这些真正的大神给我们提供了这么优秀的书籍!这是这个程序的运行结果,

  那个第一行是我特意设置的,那个root是一个文件夹的名字,是属于root用户的,所以我这里并不能读取,会报出一个错误!下面是这个改进后的程序和原来书中的程序的一个对比,发现效率还真的是提高不少啊!

  那个descend_hierarchy_p的那个程序是书上给的程序,每回读取都是读取的绝对路径的名称!而那个descend_hierarchy_ch命令就是每回碰到一个目录就进入到那个文件夹中,然后再来读取,这样每回读取的时候读取的就是相对路径的名称了!

原文地址:https://www.cnblogs.com/bwangel23/p/4121741.html