1. 概述
在 Linux C 中能够通过以下 3 种形式进行目录的遍历
- (1)应用 readdir
- (2)应用 glob
- (3)应用 nftw
2. 应用 readdir 遍历
readdir 实际上是一系列函数的汇合,它们应用的是相似于读写文件格调的 API,包含的次要函数有:
opendir
readdir
seekdir
telldir
rewinddir
closedir
读写的过程如下:
- 调用 opendir 关上一个目录(参数是门路)
- 将 errno 置为空(因为 readdir 在谬误和失常完结时都返回 NULL,无奈通过返回值确定是哪种状况,须要借助于 errno)
- 在循环中调用 readdir 遍历整个目录(留神:readdir 只遍历一层目录,如果想遍历整个目录树,须要本人应用递归进行)
- 退出循环后应用 close 敞开
根本的一个应用示例如下:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {if (argc != 2) {fprintf(stderr, "usage: %s <dir>\n", argv[0]);
exit(1);
}
DIR *dir = opendir(argv[1]);
if (dir == NULL) {perror("opendir()");
exit(1);
}
errno = 0;
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0)
continue;
printf("%s\n", entry->d_name);
}
closedir(dir);
exit(0);
}
3. 应用 glob 遍历
glob 的 API 有点相似于解析 main 函数中参数 argc 和 argv 的格调, 并且 glob 的遍历中提供了对于目录中文件名的通配符匹配,函数原型如下:
#include <glob.h>
int glob(
const char *pattern, // 文件名的通配符
int flags, // 对搜寻后果进行过滤
int (*errfunc) (const char *epath, int eerrno),// 如果报错,那么会进行回调的函数
glob_t *pglob // 最终收集后果的构造体
);
// 开释 pglob 的申请的空间
void globfree(glob_t *pglob);
根本的一个示例程序如下:
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 因为 glob 调用第 3 个参数设置成了 NULL,因而这个函数
// 没有用到
int errfunc(const char *errpath, int err) {puts(errpath);
fprintf(stderr, "glob error: %s\n", strerror(err));
}
int main(int argc, char **argv) {if (argc != 2) {fprintf(stderr, "usage: %s <dir>\n", argv[0]);
exit(1);
}
glob_t globres;
char buf[128];
bzero(buf, 128);
sprintf(buf, "%s/*", argv[1]);
int err = glob(buf, 0, NULL, &globres);
if (err) {printf("Error code = %d\n", err);
exit(1);
}
for (int i = 0; i < globres.gl_pathc; i++) {printf("%s\n", globres.gl_pathv[i]);
}
globfree(&globres);
}
这个函数实现的成果和 readdir 略有差异,如果咱们不设置 flag,那么默认失去的文件汇合中不蕴含暗藏文件
4. 应用 nftw 遍历
在遍历目录的时候应用 nftw 是更好的一种抉择
- 它能够解决在遍历的过程中可能呈现的目录被挪动、重命名和删除的状况(被其余过程进行改变)
- nftw 默认是进行整个目录的递归遍历
tips:在应用这个函数之前须要在 #include<ftw.h> 之前先定义#define _XOPEN_SOURCE 500,或者是在编译选项中退出宏定义 gcc -D_XOPEN_SOURCE=500,又或者在 Makefile 中增加 -D_OXPEN_SOURCE=500,否则会报编译谬误
这个 nftw 的大部分解决工作都是在回调函数内,回调函数提供了大量对于遍历到的文件和目录的信息(包含它们的名称,它们的 stat,以及它们所处的层级),这些信息都是回调函数的参数传递给咱们,咱们只须要在回调函数外部应用这些参数即可
一个相似于下面程序的示例(默认 nftw 打印所有层级 [递归] 的形式,为了只输入一层须要额定做一些 flag 的设置)
#define _GNU_SOURCE
#define _XOPEN_SOURCE 700
#include <errno.h>
#include <ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 每一层级应用一个文件描述符,15 层深的目录
// 曾经十分可观了
#define NUM_FDS 15
#define DEPTH_LIMIT 1
int print_entry(const char *filepath, const struct stat *info,
const int typeflag, struct FTW *ftwbuf) {// 跳过最外层的参数 argv[1]目录名的输入
if (ftwbuf->level == 0)
return FTW_CONTINUE;
if (DEPTH_LIMIT == ftwbuf->level == DEPTH_LIMIT && FTW_D == typeflag) {printf("%s\n", filepath);
return FTW_SKIP_SUBTREE; // don't get into the directory
} else {printf("%s\n", filepath);
return FTW_CONTINUE;
}
}
int main(int argc, char **argv) {if (argc != 2) {fprintf(stderr, "usage: %s <dir>\n", argv[1]);
exit(1);
}
int result =
nftw(argv[1], print_entry, NUM_FDS, FTW_PHYS | FTW_ACTIONRETVAL);
exit(0);
}
5. 参考资料
1.How to recursively list directories in C on Linux?
2.using nftw to only traverse the folder specified