【问题标题】:How to list all subdirectories in a given directory in C?如何在C中列出给定目录中的所有子目录?
【发布时间】:2010-12-15 22:21:58
【问题描述】:

有没有办法在 C 中列出给定目录路径中的所有子目录?我希望我能够使用 stat() 函数来实现它,但它只适用于文件。

【问题讨论】:

  • Richie: stat() 至少应该表明它是一个 UNIXoid 操作系统。
  • stat() 对文件起作用是正确的,但目录条目也是文件。所以stat("/etc/passwd", &buf) 和stat("/etc/", &buf) 都可以工作。
  • 操作系统是Linux。
  • 我的总体目标是使用线程来查找给定目录和子目录的大小。我试图通过查找给定目录中有多少子目录然后创建该数量的线程来解决这个问题。
  • 这不是一个真正的 C 问题。这是一个平台问题(我猜是 Linux),最后加上“我正在使用 C”。

标签: c linux list directory subdirectory


【解决方案1】:

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;
}

【讨论】:

  • 谢谢,我有很多你用来理解发生了什么的功能,而且它有效!
  • 因为这似乎是一个很好的答案,所以我对其进行了一些编辑以使其更加健壮 - 将 stat 替换为 fstatat (这意味着您不必为创建完整路径,并避免竞争条件),并处理来自 opendir 和 fstatat 的错误(这在实践中很有可能发生 - 例如“权限被拒绝”)。
  • @GuyL 您的编辑很遗憾被拒绝。我不知道很多直接的 UNIX api 东西,但如果你添加正确的包含,可能会更容易获得批准,因此很容易验证它是否可以编译。
【解决方案2】:

你想要readdir(3)。

【讨论】:

  • 谢谢,我会试一试的。
【解决方案3】:
/*
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;
}

【讨论】:

    【解决方案4】:

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

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

    要递归列出所有目录的名称,请使用 ftw(3) 或 nftw(3) 函数执行“文件树遍历”(它们的名称从何而来;“n”代表“新”)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-19
      • 2011-11-09
      • 1970-01-01
      • 2012-02-26
      • 1970-01-01
      • 2011-11-09
      • 2014-03-08
      • 2016-01-16
      相关资源
      最近更新 更多