C - 递归打印出目录和文件

时间:2015-11-08 01:13:40

标签: c file recursion printing

我需要帮助以递归方式使用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在文件夹中是随机的,当它不是时):

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

如果我将Untitled.txt重命名为apple.txt之类的东西,那么它会打印出来。这让我相信,它按字母顺序排列。

如何让它首先打印出所有文件然后进入文件夹并打印出那里的所有文件然后重复?那么打印文件>进入文件夹>重复。

1 个答案:

答案 0 :(得分:1)

问题在于:

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