如何在Linux的C语言中查找一个目录及其子目录中的文件?

3
我想编写一个程序,给定文件名后,在当前目录及其子目录中搜索该文件,并输出包含该文件的子目录名称。但是我的代码只会输出子目录名称。
#include <dirent.h>
#include <stdio.h>
#include <string.h>

void listDir(char *path, char *name)
{
    DIR *dir;
    struct dirent *ent;
    if ((dir = opendir(path)) != NULL) {
        while (( ent = readdir(dir)) != NULL) {
            if (ent->d_type == DT_REG && name == ent->d_name) {
                printf("%s\n", ent->d_name);
            }

            if (ent->d_type == DT_DIR && strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) {
                printf("%s\n", ent->d_name);
                listDir("/home/dir1/ent->d_name", name);
            }
        }
        closedir(dir);
    }
}

void main()
{
    listDir("/home/dir1", "file1");
}

2
strcmp(ent->$ 似乎有些东西丢失了。 - MikeCAT
man nftw .... - William Pursell
1
为什么不使用 nftw()scandir() 或者 glob() 来实现这个功能呢?我真的希望新的 POSIX C 程序员能够学会使用适当的 POSIX 接口,而非 opendir()/readdir()/closedir()。这些适当的接口包括 nftw()、scandir()、glob() 和 wordexp()。 - Glärbo
2个回答

0
你需要跟踪完整路径或进入每个目录。(如果您正在查看 foo/bar/baz,则如果您在顶级目录中,则 opendir("baz") 将失败。)可以尝试以下方式:
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>

void
listDir(char* path, const char *name)
{
        DIR* dir;
        struct dirent *ent;

        char *end = strrchr(path, '\0');

        if( (dir = opendir(path)) == NULL ){
                perror(path);
                return;
        } else while( (ent = readdir(dir)) != NULL ){
                if( ent->d_type == DT_DIR && strcmp(ent->d_name, ".")
                                 && strcmp(ent->d_name, "..") )
                {
                        snprintf(end, PATH_MAX - (end - path), "/%s",
                                ent->d_name);
                        listDir(path, name);
                        *end = '\0';
                } else if( !strcmp(ent->d_name, name) ){
                        printf("%s\n", path);
                }
        }
        closedir(dir);
}

int
main(int argc, char **argv)
{
        char path[PATH_MAX];
        char *defaults[] = {NULL, NULL, ".", NULL};
        if( argc < 2 ){
                printf("usage: %s name [path...]", argv[0]);
                return EXIT_SUCCESS;
        }
        const char *name = argv[1];
        if( argc < 3 ){
                argv = defaults;
        }
        for( argv += 2; *argv; argv += 1 ){
                /* getcwd(fullpath, PATH_MAX); */
                snprintf(path, PATH_MAX, "%s", *argv);
                listDir(path, name);
        }
        return 0;
}

strrchr(path, '\0'); 是计算字符串长度的一种巧妙方式... - chqrlie

0

你的代码存在多个问题:

  • 比较 name == ent->d_name 对于字符串指针无效,应该使用 !strcmp(name, ent->d_name)

  • listDir("/home/dir1/ent->d_name", name); 不能 神奇地 连接字符串。你应该使用 snprintf 或者 asprintf(在 Linux 和 BSD 系统上)来构造子目录名。

这是修改后的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void listDir(const char *path, const char *name) {
    DIR *dir;
    struct dirent *ent;

    if ((dir = opendir(path)) != NULL) {
        while ((ent = readdir(dir)) != NULL) {
            if (ent->d_type == DT_REG && !strcmp(name, ent->d_name)) {
                printf("%s\n", path);
            }
            if (ent->d_type == DT_DIR && strcmp(ent->d_name, ".")
                                      && strcmp(ent->d_name, "..")) {
                char *subdir;
                size_t len = strlen(path);
                const char *sep = "/";
                if (len && path[len - 1] == '/')
                    sep++;
                if (asprintf(&subdir, "%s%s%s", path, sep, ent->d_name) > 0) {
                    listDir(subdir, name);
                    free(subdir);
                }
            }
        }
        closedir(dir);
    }
}

int main(int argc, char *argv[]) {
    if (argc == 3) {
        listDir(argv[1], argv[2]);
    } else {
        fprintf(stderr, "usage: %s FILE DIR\n", argv[0]);
    }
    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接