1. 概述

在Linux C中能够通过以下3种形式进行目录的遍历

  • (1)应用readdir
  • (2)应用glob
  • (3)应用nftw

2. 应用readdir遍历

readdir实际上是一系列函数的汇合,它们应用的是相似于读写文件格调的API,包含的次要函数有:

opendirreaddirseekdirtelldirrewinddirclosedir

读写的过程如下:

  1. 调用opendir关上一个目录(参数是门路)
  2. 将errno置为空(因为readdir在谬误和失常完结时都返回NULL,无奈通过返回值确定是哪种状况,须要借助于errno)
  3. 在循环中调用readdir遍历整个目录(留神:readdir只遍历一层目录,如果想遍历整个目录树,须要本人应用递归进行)
  4. 退出循环后应用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 1int 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