C语言 - 递归打印目录和文件

3
我可以帮你进行翻译。需要使用C语言递归地打印文件和目录(包括子目录和文件),以下是代码示例:
char filepath[250], filename[250];

void listdir(char *dir)
{
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;

    if((dp = opendir(dir)) == NULL) 
    {
        fprintf(stderr,"cannot open directory: %s\n", dir);
        return;
    }
    chdir(dir);

    while((entry = readdir(dp)) != NULL) 
    {
        if(lstat(entry->d_name, &statbuf) == 0)
        {
            if(statbuf.st_mode & S_IFDIR)
            {
                /* Found a directory, but ignore . and .. */
                if(strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)
                    continue;

                // Concatenate directory name
                strcat(filepath, entry->d_name);
                strcat(filepath, "/");

                /* Recurse at a new indent level */
                listdir(entry->d_name);
            }
            else
            {
                // Concatenate file name
                strcpy(filename, filepath);
                strcat(filename, entry->d_name);
                puts(filename);
            }
        }
    }

    chdir("..");
    closedir(dp);
}

我注意到这段代码存在两个问题。假设这是我的文件结构:

index.c
main.c
test.o
test/hello.txt
test/Untitled.txt
test/random/

当我运行上述程序时,根据文件结构,可能会有两种不同的输出结果。
一种可能情况是(这种情况下,它会说Untitled.txt在random文件夹中,但实际上并不在):
index.c
main.c
test.o
test/hello.txt
test/random/Untitled.txt

如果我将Untitled.txt重命名为类似apple.txt的名称,则它将正常打印。这使我相信,它是按字母顺序排列的。
我该如何使其先打印所有文件,然后进入文件夹并打印其中的所有文件,然后重复此过程?因此,打印文件>进入文件夹>重复。

你用来打印文件名的变量path在哪里?你填充了变量filepath但是使用了path,是这样吗? - undefined
那是个打字错误。已经改成了文件路径。 - undefined
2
如果在random的同一级目录下还有另一个目录,会发生什么?您从filepath中没有删除当前目录名,因此当退出random并进入另一个目录后将生成无效的路径。这可能也是您问题的原因。 - undefined
谢谢,你是对的。我需要删除之前的条目。 - undefined
1个回答

2
问题在这里:

strcat(filepath, entry->d_name);
strcat(filepath, "/");

/* Recurse at a new indent level */
listdir(entry->d_name);

你正在将内容添加到之前 filepath 中的任何值中。因此,每当你从一个目录回来时,你都会将值附加到在较低级别目录中设置 filepath 的值。
在从递归调用返回后,你需要删除你添加的条目以及可能已经在较低级别添加的其他条目。
int len = strlen(filepath);
strcat(filepath, entry->d_name);
strcat(filepath, "/");

/* Recurse at a new indent level */
listdir(entry->d_name);

/* cleanup filepath */
filepath[len] = '\0';

编辑:

你也可以不使用全局变量,也不需要更改目录来完成这个操作:

void listdir(char *dir)
{
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;
    char *subdir;

    if((dp = opendir(dir)) == NULL) 
    {
        fprintf(stderr,"cannot open directory: %s\n", dir);
        return;
    }

    while((entry = readdir(dp)) != NULL) 
    {
        if(lstat(entry->d_name, &statbuf) == 0)
        {
            if(statbuf.st_mode & S_IFDIR)
            {
                /* Found a directory, but ignore . and .. */
                if(strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)
                    continue;

                // allocate space for parent directory, "/", subdir, plus NULL terminator
                subdir = malloc(strlen(dir) + strlen(entry->d_name) + 2);
                // Concatenate directory name
                strcpy(subdir, dir);
                strcat(subdir, "/");
                strcat(subdir, entry->d_name);

                /* Recurse at a new indent level */
                listdir(subdir);
                free(subdir);
            }
            else
            {
                // Print file name
                printf("%s/%s\n", dir, entry->d_name);
            }
        }
    }

    closedir(dp);
}

这个做的和之前一样。它仍然打印出test/random/Untitled.txt。 - undefined
请注意,第一个函数调用是 strcpy 而不是 strcat - undefined
是的,我在那行代码中使用了strcpy而不是strcat - undefined
1
尝试将变量filepathstrcpy(filename, filepath);处改为dir。因为如果在处理下一个文件之前找到了一个目录,你会填充filepath变量,并且这个值仍然存在。 - undefined

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