《Unix環境高級編程》這本書附帶了許多短小精美的小程序,我在閱讀此書的時候,將書上的代碼按照自己的理解重寫了一遍(大部分是抄書上的),加深一下自己的理解(純看書太困了,呵呵)。此例子在Ubuntu 10.04上測試通過。
相關鏈接
- 《UNIX環境高級編程》(第二版)apue.h的錯誤 http://www.linuxidc.com/Linux/2011-04/34662.htm
- Unix環境高級編程 源代碼地址 http://www.linuxidc.com/Linux/2011-04/34826.htm
- //《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;
- }
運行示例(加下劃線的為輸入):
www.linuxidc.com @ubuntu:~/code$ gcc temp.c -o temp
www.linuxidc.com @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 %