《Unix环境高级编程》这本书附带了许多短小精美的小程序,我在阅读此书的时候,将书上的代码按照自己的理解重写了一遍(大部分是抄书上的),加深一下自己的理解(纯看书太困了,呵呵)。此例子在Ubuntu10.04上测试通过。
程序简介:这是一个遍历文件层次结构的程序,目的是得到各种类型的文件数及其所占的比例。
//《APUE》程序4-7: //递归遍历目录层次结构,并按文件类型计数 #include <unistd.h> #include <utime.h> #include <dirent.h> #include <sys/stat.h> #include <stdio.h> #include <limits.h> #include <stdlib.h> #include <string.h> typedef int Myfunc(const char*, const struct stat*, int); static Myfunc myfunc; static int myftw(char*, Myfunc*); static int dopath(Myfunc*); static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot; int main(int argc, char **argv) { int ret; if( argc != 2 ) { fprintf(stderr, "Usage: ftw <starting-pathname>\n"); exit(1); } ret = myftw(argv[1], myfunc); ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock; // if( 0 == ntot ) ntot = 1; //输入各种文件的数量及所占的比例 printf("reglar files = %7ld, %5.2lf %% \n", nreg, nreg*100.0/ntot); printf("directories = %7ld, %5.2lf %% \n", ndir, ndir*100.0/ntot); printf("block special = %7ld, %5.2lf %% \n", nblk, nblk*100.0/ntot); printf("char special = %7ld, %5.2lf %% \n", nchr, nchr*100.0/ntot); printf("FIFOs = %7ld, %5.2lf %% \n", nfifo, nfifo*100.0/ntot); printf("symbolic links = %7ld, %5.2lf %% \n", nslink, nslink*100.0/ntot); printf("sockets = %7ld, %5.2lf %% \n", nsock, nsock*100.0/ntot); return ret; } #define FTW_F 1 #define FTW_D 2 #define FTW_DNR 3 #define FTW_NS 4 static char *fullpath; static int myftw(char *pathname, Myfunc *func) { //《APUE》书中,这个功能用了一个很复杂的函数path_alloc()来实现 //这里我为了简单起见,直接为它分配了一段内存完事 #ifdef PATH_MAX const int PATH_LEN = PATH_MAX; #else const int PATH_LEN = 1024; #endif fullpath = malloc(PATH_LEN); strncpy(fullpath, pathname, PATH_LEN); fullpath[PATH_LEN-1] = '\0'; int res = dopath(func); //《APUE》书中,好像没有释放这段内存 free(fullpath); return res; } static int dopath(Myfunc* func) { struct stat statbuf; struct dirent *dirp; DIR *dp; int ret; char *ptr; int temp; temp = lstat(fullpath, &statbuf); //文件状态错误 if( temp < 0 ) return func(fullpath, &statbuf, FTW_NS); temp = S_ISDIR(statbuf.st_mode); //不是文件夹 if( 0 == temp ) return func(fullpath, &statbuf, FTW_F); ret = func(fullpath, &statbuf, FTW_D); if( ret != 0 ) return ret; ptr = fullpath + strlen(fullpath); *ptr++ = '/'; *ptr = 0; dp = opendir(fullpath); //不能读取该文件夹 if( NULL == dp ) return func(fullpath, &statbuf, FTW_DNR); while( (dirp = readdir(dp)) != NULL ) { //忽略.和..这两个文件夹 if( strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0 ) continue; strcpy(ptr, dirp->d_name); //递归遍历各个子文件夹 ret = dopath(func); if( ret != 0 ) break; } ptr[-1] = 0; if( closedir(dp) < 0 ) { fprintf(stderr, "can't close directory %s\n", fullpath); } return ret; } 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++; printf("reg: %s\n", fullpath); break; case S_IFBLK: nblk++; printf("blk: %s\n", fullpath); break; case S_IFCHR: nchr++; printf("chr: %s\n", fullpath); break; case S_IFIFO: nfifo++; printf("fifo: %s\n", fullpath); break; case S_IFLNK: nslink++; printf("slink: %s\n", fullpath); break; case S_IFSOCK: nsock++; printf("socket: %s\n", fullpath); break; case S_IFDIR: fprintf(stderr, "For S_IFDIR for %s\n", pathname); exit(1); } //《APUE》书中没有输出遍历的结果,这个是我自己加上去的 break; case FTW_D: ndir++; printf("DIR: %s\n", fullpath); break; case FTW_DNR: fprintf(stderr, "can't read directory %s\n", pathname); break; case FTW_NS: fprintf(stderr, "stat error for %s\n", pathname); break; default: fprintf(stderr, "unkown type %d for pathname %s\n", type, pathname); } return 0; }
运行示例(红色字体的为输入):
qch@ubuntu:~/code$ gcc temp.c -o temp
qch@ubuntu:~/code$ ./temp /etc
DIR: /etc
DIR: /etc/sudoers.d
reg: /etc/sudoers.d/README
...............
reglar files = 1593, 59.89 %
directories = 306, 11.50 %
block special = 0, 0.00 %
char special = 0, 0.00 %
FIFOs = 0, 0.00 %
symbolic links = 761, 28.61 %
sockets = 0, 0.00 %