歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 《APUE》:遞歸遍歷目錄層次結構,並按文件類型計數

《APUE》:遞歸遍歷目錄層次結構,並按文件類型計數

日期:2017/3/1 10:12:04   编辑:Linux編程

《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
  1. //《APUE》程序4-7:
  2. //遞歸遍歷目錄層次結構,並按文件類型計數
  3. #include <unistd.h>
  4. #include <utime.h>
  5. #include <dirent.h>
  6. #include <sys/stat.h>
  7. #include <stdio.h>
  8. #include <limits.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. typedef int Myfunc(const char*, const struct stat*, int);
  12. static Myfunc myfunc;
  13. static int myftw(char*, Myfunc*);
  14. static int dopath(Myfunc*);
  15. static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;
  16. int main(int argc, char **argv)
  17. {
  18. int ret;
  19. if( argc != 2 )
  20. {
  21. fprintf(stderr, "Usage: ftw <starting-pathname>\n");
  22. exit(1);
  23. }
  24. ret = myftw(argv[1], myfunc);
  25. ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;
  26. //
  27. if( 0 == ntot )
  28. ntot = 1;
  29. //輸入各種文件的數量及所占的比例
  30. printf("reglar files = %7ld, %5.2lf %% \n",
  31. nreg, nreg*100.0/ntot);
  32. printf("directories = %7ld, %5.2lf %% \n",
  33. ndir, ndir*100.0/ntot);
  34. printf("block special = %7ld, %5.2lf %% \n",
  35. nblk, nblk*100.0/ntot);
  36. printf("char special = %7ld, %5.2lf %% \n",
  37. nchr, nchr*100.0/ntot);
  38. printf("FIFOs = %7ld, %5.2lf %% \n",
  39. nfifo, nfifo*100.0/ntot);
  40. printf("symbolic links = %7ld, %5.2lf %% \n",
  41. nslink, nslink*100.0/ntot);
  42. printf("sockets = %7ld, %5.2lf %% \n",
  43. nsock, nsock*100.0/ntot);
  44. return ret;
  45. }
  46. #define FTW_F 1
  47. #define FTW_D 2
  48. #define FTW_DNR 3
  49. #define FTW_NS 4
  50. static char *fullpath;
  51. static int myftw(char *pathname, Myfunc *func)
  52. {
  53. //《APUE》書中,這個功能用了一個很復雜的函數path_alloc()來實現
  54. //這裡我為了簡單起見,直接為它分配了一段內存完事
  55. #ifdef PATH_MAX
  56. const int PATH_LEN = PATH_MAX;
  57. #else
  58. const int PATH_LEN = 1024;
  59. #endif
  60. fullpath = malloc(PATH_LEN);
  61. strncpy(fullpath, pathname, PATH_LEN);
  62. fullpath[PATH_LEN-1] = '\0';
  63. int res = dopath(func);
  64. //《APUE》書中,好像沒有釋放這段內存
  65. free(fullpath);
  66. return res;
  67. }
  68. static int dopath(Myfunc* func)
  69. {
  70. struct stat statbuf;
  71. struct dirent *dirp;
  72. DIR *dp;
  73. int ret;
  74. char *ptr;
  75. int temp;
  76. temp = lstat(fullpath, &statbuf);
  77. //文件狀態錯誤
  78. if( temp < 0 )
  79. return func(fullpath, &statbuf, FTW_NS);
  80. temp = S_ISDIR(statbuf.st_mode);
  81. //不是文件夾
  82. if( 0 == temp )
  83. return func(fullpath, &statbuf, FTW_F);
  84. ret = func(fullpath, &statbuf, FTW_D);
  85. if( ret != 0 )
  86. return ret;
  87. ptr = fullpath + strlen(fullpath);
  88. *ptr++ = '/';
  89. *ptr = 0;
  90. dp = opendir(fullpath);
  91. //不能讀取該文件夾
  92. if( NULL == dp )
  93. return func(fullpath, &statbuf, FTW_DNR);
  94. while( (dirp = readdir(dp)) != NULL )
  95. {
  96. //忽略.和..這兩個文件夾
  97. if( strcmp(dirp->d_name, ".") == 0 ||
  98. strcmp(dirp->d_name, "..") == 0 )
  99. continue;
  100. strcpy(ptr, dirp->d_name);
  101. //遞歸遍歷各個子文件夾
  102. ret = dopath(func);
  103. if( ret != 0 )
  104. break;
  105. }
  106. ptr[-1] = 0;
  107. if( closedir(dp) < 0 )
  108. {
  109. fprintf(stderr, "can't close directory %s\n", fullpath);
  110. }
  111. return ret;
  112. }
  113. static int myfunc(const char *pathname, const struct stat *statptr, int type)
  114. {
  115. switch(type)
  116. {
  117. case FTW_F:
  118. switch( statptr->st_mode & S_IFMT )
  119. {
  120. case S_IFREG:
  121. nreg++;
  122. printf("reg: %s\n", fullpath);
  123. break;
  124. case S_IFBLK:
  125. nblk++;
  126. printf("blk: %s\n", fullpath);
  127. break;
  128. case S_IFCHR:
  129. nchr++;
  130. printf("chr: %s\n", fullpath);
  131. break;
  132. case S_IFIFO:
  133. nfifo++;
  134. printf("fifo: %s\n", fullpath);
  135. break;
  136. case S_IFLNK:
  137. nslink++;
  138. printf("slink: %s\n", fullpath);
  139. break;
  140. case S_IFSOCK:
  141. nsock++;
  142. printf("socket: %s\n", fullpath);
  143. break;
  144. case S_IFDIR:
  145. fprintf(stderr, "For S_IFDIR for %s\n", pathname);
  146. exit(1);
  147. }
  148. //《APUE》書中沒有輸出遍歷的結果,這個是我自己加上去的
  149. break;
  150. case FTW_D:
  151. ndir++;
  152. printf("DIR: %s\n", fullpath);
  153. break;
  154. case FTW_DNR:
  155. fprintf(stderr, "can't read directory %s\n", pathname);
  156. break;
  157. case FTW_NS:
  158. fprintf(stderr, "stat error for %s\n", pathname);
  159. break;
  160. default:
  161. fprintf(stderr, "unkown type %d for pathname %s\n",
  162. type, pathname);
  163. }
  164. return 0;
  165. }

運行示例(加下劃線的為輸入):

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 %

Copyright © Linux教程網 All Rights Reserved