读目录

读目录

头文件<dirent.h>相关函数介绍

    对某个目录具有访问权限的任何用户都可以读目录
    但是,为了防止文件系统产生混乱,只有内核才能写目录
    一个目录的写权限位和执行权限位决定了在该目录中能否创建新文件以及删除文件,并不是能否写目录本身
    UNIX现在包含了一套与目录有关的程序,它们是POSIX.1的一部分。很多实现阻止应用程序使用read函数去读取目录的内容,由此进一步将应用程序与目录中实现相关的细节隔离。
  1. #include<dirent.h>
  2. DIR*opendir(constchar*pathname);
  3. DIR*fdopendir(int fd);
  4. Bothreturn: pointer if OK, NULL on error
  5. struct dirent *readdir(DIR*dp);
  6. Returns: pointer if OK, NULL at end of directory or error
  7. void rewinddir(DIR*dp);
  8. int closedir(DIR*dp);
  9. Returns:0if OK,1 on error
  10. long telldir(DIR*dp);
  11. Returns: current location in directory associated with dp
  12. void seekdir(DIR*dp,long loc);
图1 <dirent.h>文件里的函数原型
  telldirseekdir函数不是基本POSIX.1标准组成部分,是Single UNIX Specification中的XSI扩展
    定义在<dirent.h>头文件中的dirent结构与实现有关,实现此结构体的定义至少包含下列两个成员:
ino_t d_ino;                  /* i-node number */
char  d_name[];           /* null-terminated filename */
    注意,d_name项的大小没有指定,但必须保证它能包含至少NAME_MAX个字节(不包含终止null字节)
    DIR结构是一个内部结构,上述7个函数用这个内部结构保存当前正在被读的目录的有关信息
    由opendirfdopendir返回的指向DIR结构的指针由另外5个函数使用
    opendir执行初始化操作,使第一个readdir返回目录中的第一个目录项
    注意,目录中各个目录项的顺序与实现有关,它们通常并不按字母顺序排序

实例

    编写一个遍历文件层次结构的程序,并统计各种类型文件的数量
  1. /**
  2. * 文件内容: 编写一个遍历文件层次结构的程序,并统计各种类型文件的数量
  3. * 文件时间: 2016年 11月 13日 星期日 15:30:31 CST
  4. * 作者: firewaywei@126.com
  5. */
  6. #include<stdio.h>
  7. #include<sys/types.h>
  8. #include<sys/stat.h>
  9. #include<unistd.h>
  10. #include<dirent.h>
  11. #include<string.h>
  12. #include<stdarg.h>// ISO C variable aruments
  13. #include<stdlib.h>
  14. #include<errno.h>
  15.  
  16. #define MAXLINE 4096// max line length
  17.  
  18. // function type that is called for each filename
  19. typedefintMyFunc(constchar*,conststruct stat *,int);
  20. staticMyFunc g_myFunc;
  21. staticchar*g_fullPath;
  22. staticsize_t g_pathLen;
  23. staticlong g_nTotal =0L;
  24. staticlong g_nReg =0L;
  25. staticlong g_nDir =0L;
  26. staticlong g_nBlk =0L;
  27. staticlong g_nChr =0L;
  28. staticlong g_nFifo =0L;
  29. staticlong g_nSlink =0L;
  30. staticlong g_nSock =0L;
  31. #define FTW_F 1/* file other than directory */
  32. #define FTW_D 2/* directory */
  33. #define FTW_DNR 3/* directory that can't be read */
  34. #define FTW_NS 4/* file that we can't stat */
  35. staticvoid err_doit(int,int,constchar*, va_list);
  36. staticint myFtw(char*,MyFunc*);
  37. staticint doPath(MyFunc*myFunc);
  38. /**
  39. * Print a message and return to caller.
  40. * Caller specifies "errnoflag".
  41. */
  42. staticvoid err_doit(int errnoflag,int error,constchar*fmt, va_list ap)
  43. {
  44. char buf[MAXLINE]={0};
  45. vsnprintf(buf, MAXLINE -1, fmt, ap);
  46. if(errnoflag)
  47. {
  48. snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1,": %s",
  49. strerror(error));
  50. }
  51. strcat(buf,"\n");
  52. fflush(stdout);/* in case stdout and stderr are the same */
  53. fputs(buf, stderr);
  54. fflush(NULL);/* flushes all stdio output streams */
  55. }
  56. /**
  57. * Fatal error unrelated to a system call.
  58. * Print a message and terminate.
  59. */
  60. staticvoid err_quit(constchar*fmt,...)
  61. {
  62. va_list ap;
  63. va_start(ap, fmt);
  64. err_doit(0,0, fmt, ap);
  65. va_end(ap);
  66. exit(1);
  67. }
  68. /**
  69. * Nonfatal error related to a system call.
  70. * Print a message and return.
  71. */
  72. staticvoid err_ret(constchar*fmt,...)
  73. {
  74. va_list ap;
  75. va_start(ap, fmt);
  76. err_doit(1, errno, fmt, ap);
  77. va_end(ap);
  78. }
  79. /**
  80. * Fatal error related to a system call.
  81. * Print a message and terminate.
  82. */
  83. staticvoid err_sys(constchar*fmt,...)
  84. {
  85. va_list ap;
  86. va_start(ap, fmt);
  87. err_doit(1, errno, fmt, ap);
  88. va_end(ap);
  89. exit(1);
  90. }
  91. /**
  92. * Fatal error related to a system call.
  93. * Print a message, dump core, and terminate.
  94. */
  95. staticvoid err_dump(constchar*fmt,...)
  96. {
  97. va_list ap;
  98. va_start(ap, fmt);
  99. err_doit(1, errno, fmt, ap);
  100. va_end(ap);
  101. abort();/* dump core and terminate */
  102. exit(1);/* shouldn't get here */
  103. }
  104. int main(int argc,char** argv)
  105. {
  106. int ret =0;
  107. if(argc !=2)
  108. {
  109. err_quit("usage: ftw <starting-pathname>");
  110. }
  111. ret = myFtw(argv[1], g_myFunc);
  112. g_nTotal = g_nReg + g_nDir + g_nBlk + g_nChr + g_nFifo + g_nSlink + g_nSock;
  113. if(0== g_nTotal)
  114. {
  115. g_nTotal =1L;
  116. }
  117. printf("regular files = %7ld, %5.2f %%\n", g_nReg, g_nReg *100.0/ g_nTotal);
  118. printf("directories = %7ld, %5.2f %%\n", g_nDir, g_nDir *100.0/ g_nTotal);
  119. printf("block special = %7ld, %5.2f %%\n", g_nBlk, g_nBlk *100.0/ g_nTotal);
  120. printf("char special = %7ld, %5.2f %%\n", g_nChr, g_nChr *100.0/ g_nTotal);
  121. printf("FIFOS = %7ld, %5.2f %%\n", g_nFifo, g_nFifo *100.0/ g_nTotal);
  122. printf("symbolic links = %7ld, %5.2f %%\n", g_nSlink, g_nSlink *100.0/ g_nTotal);
  123. printf("sockets = %7ld, %5.2f %%\n", g_nSock, g_nSock *100.0/ g_nTotal);
  124. // remember free
  125. if(g_fullPath != NULL)
  126. {
  127. free(g_fullPath);
  128. g_fullPath = NULL;
  129. }
  130. exit(ret);
  131. }
  132. staticlong g_posix_version =0L;
  133. staticlong g_xsi_version =0L;
  134. #ifdef PATH_MAX
  135. staticlong g_pathMax = PATH_MAX;
  136. #else
  137. staticlong g_pathMax =0;
  138. #endif
  139. /* If PATH_MAX is indeterminate, no guarantee this is adequate */
  140. #define PATH_MAX_GUESS 1024
  141. char*path_alloc(size_t*sizep)
  142. {
  143. char*ptr = NULL;
  144. size_t size =0;
  145. if(g_posix_version ==0)
  146. {
  147. g_posix_version = sysconf(_SC_VERSION);
  148. }
  149. if(g_xsi_version ==0)
  150. {
  151. g_xsi_version = sysconf(_SC_XOPEN_VERSION);
  152. }
  153. if(g_pathMax ==0)
  154. {
  155. /* first time through */
  156. errno =0;
  157. if((g_pathMax = pathconf("/", _PC_PATH_MAX))<0)
  158. {
  159. if(errno ==0)
  160. {
  161. g_pathMax = PATH_MAX_GUESS;/* it's indeterminate */
  162. }
  163. else
  164. {
  165. err_sys("pathconf error for _PC_PATH_MAX");
  166. }
  167. }
  168. else
  169. {
  170. g_pathMax++;/* add one since it's relative to root */
  171. }
  172. }
  173. /*
  174. * Before POSIX.1-2001, we aren't guaranteed that PATH_MAX includes
  175. * the terminating null byte. Same goes for XPG3.
  176. */
  177. if((g_posix_version <200112L)&&(g_xsi_version <4))
  178. {
  179. size = g_pathMax +1;
  180. }
  181. else
  182. {
  183. size = g_pathMax;
  184. }
  185. if((ptr = malloc(size))== NULL)
  186. {
  187. err_sys("malloc error for pathname");
  188. }
  189. if((ptr = memset(ptr,0, size))== NULL)
  190. {
  191. err_sys("memset error for pathname");
  192. }
  193. if(sizep != NULL)
  194. {
  195. *sizep = size;
  196. }
  197. return(ptr);
  198. }
  199. staticint myFtw(char*pathName,MyFunc*myFunc)
  200. {
  201. g_fullPath = path_alloc(&g_pathLen);
  202. if(g_pathLen < strlen(pathName))
  203. {
  204. g_pathLen = strlen(pathName)*2;
  205. if(realloc(g_fullPath, g_pathLen)== NULL)
  206. {
  207. err_sys("realloc failed");
  208. }
  209. }
  210. strcpy(g_fullPath, pathName);
  211. return doPath(myFunc);
  212. }
  213. /**
  214. * we return whatever myFunc return
  215. */
  216. staticint doPath(MyFunc*myFunc)
  217. {
  218. struct stat statBuf;
  219. if(lstat(g_fullPath,&statBuf)<0)// stat error
  220. {
  221. return myFunc(g_fullPath,&statBuf, FTW_NS);
  222. }
  223. if(S_ISDIR(statBuf.st_mode)==0)// not a diretctory
  224. {
  225. return myFunc(g_fullPath,&statBuf, FTW_F);
  226. }
  227. // It's a directory, first call myFunc() for the directory,
  228. // then process each filename in the directory.
  229. int ret =0;
  230. if(ret = myFunc(g_fullPath,&statBuf, FTW_D)!=0)
  231. {
  232. return ret;
  233. }
  234. int n = strlen(g_fullPath);
  235. if(n + NAME_MAX +2> g_pathLen)// expand path buffer
  236. {
  237. g_pathLen *=2;
  238. if((g_fullPath = realloc(g_fullPath, g_pathLen))== NULL)
  239. {
  240. err_sys("realloc failed");
  241. }
  242. }
  243. g_fullPath[n++]='/';
  244. g_fullPath[n]='\0';
  245. DIR*dp = NULL;
  246. if((dp = opendir(g_fullPath))== NULL)// can't read directory
  247. {
  248. return myFunc(g_fullPath,&statBuf, FTW_DNR);
  249. }
  250. struct dirent *pDir = NULL;
  251. while((pDir = readdir(dp))!= NULL)
  252. {
  253. if(0== strcmp(".", pDir->d_name)||0== strcmp("..", pDir->d_name))
  254. {
  255. continue;// ignore dot and dot-dot
  256. }
  257. strcpy(&(g_fullPath[n]), pDir->d_name);// append name after "/"
  258. if((ret = doPath(myFunc))!=0)// recursive
  259. {
  260. break;// time to leave
  261. }
  262. }
  263. g_fullPath[n -1]='\0';// erase everything from slash onward
  264. if(closedir(dp)<0)
  265. {
  266. err_ret("can't close directory %s", g_fullPath);
  267. }
  268. return ret;
  269. }
  270. staticint ftw_f(constchar*pathName,conststruct stat *statPtr,int type)
  271. {
  272. switch(statPtr->st_mode & S_IFMT)
  273. {
  274. case S_IFREG:
  275. g_nReg++;
  276. break;
  277. case S_IFBLK:
  278. g_nBlk++;
  279. break;
  280. case S_IFCHR:
  281. g_nChr++;
  282. break;
  283. case S_IFIFO:
  284. g_nFifo++;
  285. break;
  286. case S_IFLNK:
  287. g_nSlink++;
  288. break;
  289. case S_IFSOCK:
  290. g_nSock++;
  291. break;
  292. case S_IFDIR:// directories should have type = FTW_D
  293. err_dump("for S_IFDIR for %s, directories should have type = FTW_D", pathName);
  294. break;
  295. default:
  296. err_dump("%s unknown type %d for pathname %s", __FUNCTION__, type, pathName);
  297. break;
  298. }
  299. }
  300. staticint g_myFunc(constchar*pathName,conststruct stat *statPtr,int type)
  301. {
  302. switch(type)
  303. {
  304. case FTW_F:
  305. ftw_f(pathName, statPtr, type);
  306. break;
  307. case FTW_D:
  308. g_nDir++;
  309. break;
  310. case FTW_DNR:
  311. err_ret("can't read directory %s", pathName);
  312. break;
  313. case FTW_NS:
  314. err_ret("stat error for %s", pathName);
  315. break;
  316. default:
  317. err_dump("%s unknown type %d for pathname %s", __FUNCTION__, type, pathName);
  318. break;
  319. }
  320. return0;
  321. }
图2. 递归降序遍历目录层次结构,并按文件类型计数
    程序运行如下:
$ ./a.out  .
regular files  =       4,     33.33 %
directories    =       6,     50.00 %
block special  =       0,      0.00 %
char special   =       0,      0.00 %
FIFOS          =       0,      0.00 %
symbolic links =       2,     16.67 %
sockets        =       0,      0.00 %

参考

UNIX环境高级编程(第三版)    4.22 读目录
 

 

 

posted @ 2016-11-13 15:34  fireway  阅读(185)  评论(0编辑  收藏  举报