C语言实现文件类型统计函数
#include<dirent.h> #include<limits.h> #include<sys/stat.h> #include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #define FTW_F 1 //标记非目录文件 #define FTW_D 2 //标记目录文件 #define FTW_DNR 3 //标记不可读目录 #define FTW_NS 4 //标记不可获得stat的文件 static char *fullpath; //保存文件的全路径 static size_t pathlen; //保存文件的路径长度 //定义处理文件的函数 typedef int Myfunc(const char *,const struct stat*,int); static Myfunc myfunc; static int myftw(char *,Myfunc *); static int dopath(Myfunc *); char *path_alloc(size_t *size_t); /* nreg:普通文件的个数; ndir: 目录文件的数量; nblk:块特殊文件的数量 nchr:字符特殊文件的数量 nfifo:管道特殊文件的数量 nslink:符号连接特殊文件的数量; nsock:套接字文件数量; ntot:总文件数量 */ static long nreg,ndir,nblk,nchr,nfifo,nslink,nsock,ntot; int main( int argc, char *argv[]) { int ret; if(argc != 2) { printf("falut command input !\n"); exit(1); } //计算各类文件的个数 ret = myftw(argv[1],myfunc); ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock; //避免除以0 if(ntot == 0) { ntot = 1; } printf("regular files = %7ld,%5.2f %%\n",nreg,nreg*100.0 / ntot); printf("direciotn files = %7ld,%5.2f %%\n",ndir,ndir*100.0 / ntot); printf("block special = %7ld,%5.2f %%\n",nblk,nblk*100.0 / ntot); printf("char special = %7ld,%5.2f %%\n",nchr,nchr*100.0 / ntot); printf("FIFOS = %7ld,%5.2f %%\n",nfifo,nfifo*100.0 / ntot); printf("symbolic links = %7ld,%5.2f %%\n",nslink,nslink*100.0 / ntot); printf("sockers = %7ld,%5.2f %%\n",nsock,nsock*100.0 / ntot); } //处理pathname并保存在一个全局的字符数组中,调用dopath static int myftw(char *pathname,Myfunc *func) { //为保存路径的字符串数组分配空间 fullpath = path_alloc(&pathlen); //如果分配内存空间不够就重新分配 if(pathlen <= strlen(pathname)) { pathlen = strlen(pathname) * 2; if((fullpath = realloc(fullpath,pathlen )) == NULL); printf("realloc failed\n"); } //将路径名参数保存到全路径中,fullpath是全局变量,dopath函数可以调用 strcpy(fullpath,pathname); return (dopath(func)); } //路径数组分配 char *path_alloc(size_t *size) { char *p = NULL; if(!size) return NULL; p = malloc(256); if(p) *size = 256; else *size = 0; return p; } //dopath用于判断是否是目录,然后根据选择情况是直接进入myfun函数取技术 //还是递归调用dopath函数 static int dopath(Myfunc *func) { struct stat statbuf; struct dirent *dirp; DIR *dp; int ret,n; //调用lstat获取路径名的stat信息,如果不成功,调用func函数,并传递给FTW_NS if(lstat(fullpath,&statbuf) < 0) return (func(fullpath, &statbuf, FTW_NS)); //查看文件stat结构的st_mode,如果不是目录,调用func函数 //并传递给FTW_F,交由myfun进一步判断文件类型 if(S_ISDIR(statbuf.st_mode) == 0) return(func(fullpath,&statbuf,FTW_F)); //最后一种情况就是该路径名代表的是一个目录,此次的fun的正常情况返回0 //所以执行完func后还不会返回,会继续执行func if((ret = func(fullpath,&statbuf,FTW_D)) != 0) return(ret); //路径处理,扩充路径空间长度 n = strlen(fullpath); if(n + NAME_MAX + 2 > pathlen) { pathlen *= 2; if((fullpath = realloc(fullpath,pathlen)) == NULL) { printf("realoc failed\n"); } } fullpath[n++] = '/'; fullpath[n] = 0; //处理每个目录项 if((dp = opendir(fullpath)) == NULL) return (func(fullpath,&statbuf,FTW_DNR)); while((dirp = readdir(dp)) != NULL) { //忽略当前目录(.)和上一级目录(..)以避免进入死循环 if(strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0 ) continue; strcpy(&fullpath[n],dirp->d_name); //在“/”之后加上当前目录项的命中 if((ret = dopath(func)) != 0) //然后采用新的路径名递递归的调用dopath break; } fullpath[n-1] = 0; //关闭目录 if(closedir(dp) < 0 ) printf("can't close directory %s",fullpath); return ret; } //通过stat结构的st_mode字段来判断文件的类型,并计数 static int myfunc(const char *pathname,const struct stat *statptr,int type) { switch(type) { //会与非目录情况进行处理 case FTW_F: switch (statptr->st_mode & S_IFMT) { case S_IFREG: nreg++; break; case S_IFBLK: nblk++; break; case S_IFCHR: nchr++; break; case S_IFIFO: nfifo++; break; case S_IFLNK: nslink++; break; case S_IFSOCK: nsock++; break; case S_IFDIR: printf("for S_IFDIR for %s",pathname); } break; //对于目录文件进行处理 case FTW_D: ndir++; break; //对于不可读目录进行处理 case FTW_DNR: printf("%s dir isn't read",pathname); break; case FTW_NS: printf("%s stat error",pathname); default: printf("%d type aren't identified, path is %s",type,pathname); } return 0; }