如何列出C中给定目录中的所有子目录?

问题描述:

有没有办法列出C中给定目录路径中的所有子目录?我希望能用stat()函数来完成它,但它只能用于文件。如何列出C中给定目录中的所有子目录?

+0

什么操作系统? – RichieHindle

+0

Richie:'stat()'应该至少说明它是一个UNIXoid操作系统。 – Joey

+1

你是正确的,'stat()'在文件上工作,但目录条目也是文件。所以'stat(“/ etc/passwd”,&buf)''和'stat(“/ etc /”,&buf)'都可以工作。 –

stat也可以在目录上工作。

#include <sys/types.h> 
#include <dirent.h> 
#include <sys/stat.h> 
#include <unistd.h> 

int num_dirs(const char* path) 
{ 
    int dir_count = 0; 
    struct dirent* dent; 
    DIR* srcdir = opendir(path); 

    if (srcdir == NULL) 
    { 
     perror("opendir"); 
     return -1; 
    } 

    while((dent = readdir(srcdir)) != NULL) 
    { 
     struct stat st; 

     if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) 
      continue; 

     if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) 
     { 
      perror(dent->d_name); 
      continue; 
     } 

     if (S_ISDIR(st.st_mode)) dir_count++; 
    } 
    closedir(srcdir); 
    return dir_count; 
} 

+0

谢谢,我用了很多你用来理解发生了什么的功能,它的工作原理! – KenjiOne

+1

因为这看起来像是一个很好的答案,所以我稍微修改了它以使它更加健壮 - 用'fstatat'替换'stat'(这意味着您不必为创建完整路径而烦恼,避免竞争条件),并处理来自“opendir”和“fstatat”的错误(这在实践中是相当可能的 - 例如“被拒绝的权限”)。 – caf

+1

@caf - 你做错了 - 忘了旗帜 - 我修好了 –

你想要readdir(3)

+0

谢谢,我会给你一个镜头。 – KenjiOne

正如其他人指出,stat(2)适用于文件和所有类型的设备很好。它通过符号链接读取远端文件;如果您需要关于符号链接本身的信息,请使用lstat(2)

要列出单个目录内所有目录的名称(非递归),请使用readdir(3)系列函数的组合。

要递归列出所有目录的名称,请使用ftw(3)nftw(3)函数来执行'文件树遍历'(来自这些文件的名字;'n'代表'new')。

/* 
I had need in something like this not so long ago (my difference is I 
needed recursive scan) so I added only some comments... Sorry for recursion 
but I was short of time and this was only part of internal one-time tool. 
*/ 

/* Print all the dirs starting from <path> [maybe recursive]. */ 
int print_dirs(const char *path, int recursive) 
{ 
    struct dirent *direntp = NULL; 
    DIR *dirp = NULL; 
    size_t path_len; 

    /* Check input parameters. */ 
    if (!path) 
     return -1; 
    path_len = strlen(path); 

    if (!path || !path_len || (path_len > _POSIX_PATH_MAX)) 
     return -1; 

    /* Open directory */ 
    dirp = opendir(path); 
    if (dirp == NULL) 
     return -1; 

    while ((direntp = readdir(dirp)) != NULL) 
    { 
     /* For every directory entry... */ 
     struct stat fstat; 
     char full_name[_POSIX_PATH_MAX + 1]; 

     /* Calculate full name, check we are in file length limts */ 
     if ((path_len + strlen(direntp->d_name) + 1) > _POSIX_PATH_MAX) 
      continue; 

     strcpy(full_name, path); 
     if (full_name[path_len - 1] != '/') 
      strcat(full_name, "/"); 
     strcat(full_name, direntp->d_name); 

     /* Ignore special directories. */ 
     if ((strcmp(direntp->d_name, ".") == 0) || 
      (strcmp(direntp->d_name, "..") == 0)) 
      continue; 

     /* Print only if it is really directory. */ 
     if (stat(full_name, &fstat) < 0) 
      continue; 
     if (S_ISDIR(fstat.st_mode)) 
     { 
      printf("%s\n", full_name); 
      if (recursive) 
       print_dirs(full_name, 1); 
     } 
    } 

    /* Finalize resources. */ 
    (void)closedir(dirp); 
    return 0; 
} 

/* We are taking first argument as initial path name. */ 
int main(int argc, const char* argv[]) 
{ 
    if (argc < 2) 
     return -1; 

    print_dirs(argv[1], 1); 
    return 0; 
}