递归打印目录及其子目录中所有文件的文件路径

时间:2016-11-19 20:00:43

标签: c recursion directory traversal

我正在开发一个项目,该项目应该打印出目录中所有文件的所有文件路径以及C中的所有子目录。基本上,它最终意味着模拟查找实用程序在Linux中。

我有以下代码:

void read_sub(char * sub_dir){
    DIR *sub_dp = opendir(sub_dir);//open a directory stream
    struct dirent * sub_dirp;//define
    struct stat buf;//define a file status structure
    char temp1[]=".";
    char temp2[]="..";
    char temp3[]="/";

    if(sub_dp!=NULL){ //Check if the directory opened successfully 

        while((sub_dirp=readdir(sub_dp))!=NULL){ //until we've read every entry one by one

            char * temp = sub_dirp -> d_name; //get the name 

            if(strcmp(temp, temp1)!=0 && strcmp(temp, temp2)!=0){ //Ignores . and .. in the directory

                char *temp_sub = temp3; // This is '/'
                temp_sub = strcat(temp_sub, temp); // Adds '/' before the name of the entry


                //now you can add the / in front of the entry's name
                char* temp_full_path=malloc(sizeof(char)*2000); //Create a variable to hold the full path

                //Place the passed directory at the front of the path and add the name of the file to the end
                temp_full_path=strcpy(temp_full_path,sub_dir); 
                strcat(temp_full_path,temp_sub);

                //try to open the file path we just created
                DIR * subsubdp = opendir(temp_full_path);


                //if not null, we've found a subdirectory, otherwise it's a file
                if(subsubdp!=NULL){
                        //close the stream because it'll be reopened in the recursive call.
                    closedir(subsubdp);
                    read_sub(temp_full_path);//call the recursive function call.
                }else{
                    printf("%s\n",temp_full_path);
                }
            }
        }//end of while loop
        closedir(sub_dp);//close the stream
    }else{
        printf("cannot open directory\n");
        exit(2);
    }
}   

我通过直接传递它" testdir"来运行它,这是一个具有以下结构的目录:

testdir/
|-- dir1
| |-- dir2
| | |-- test5
| | `-- test6
| |-- test3
| `-- test4
|-- dir3
| |-- test7
| `-- test8
|-- test1
`-- test2

因此,它应输出如下内容:

testdir/dir1/dir2/test5
testdir/dir1/dir2/test6
testdir/dir1/test3
testdir/dir1/test4

等等。但是,实际结果是:

testdir/dir1/dir2/test6
testdir/dir1/dir2/test6test5
testdir/dir1/dir2test3
testdir/dir1/dir2test3test4
testdir/dir1test1
testdir/dir1test1dir3
testdir/dir1test1dir3test2

所以看起来它可能无法在运行时正确清除完整的文件路径?此外,它似乎并没有真正进入dir3来打印test7和test8。我做错了什么?谢谢。

2 个答案:

答案 0 :(得分:1)

您没有为目标字符串分配足够的空间。您至少需要char temp1[PATH_MAX] = "."; char temp2[PATH_MAX] = ".."; char temp3[PATH_MAX] = "/"; 个字节。

尝试

snprintf()
实际上,编译器只会分配足够的空间来保存初始化字符串(2,3,2)。所以你的程序表现出不确定的行为。我建议使用strcat()代替strcat(),因为它是直接的而不是昂贵的。每次调用'\0'时,它将搜索目标字符串的当前结尾,直到找到终止{{1}}。

此外,尝试使用最少数量的缩进级别,因为代码很快变得非常难以理解。

答案 1 :(得分:0)

您可以使用S_ISDIR来测试目录。应使用malloc清除free以避免内存泄漏。在递归函数中实现malloc/free会变得太复杂,因此最好只声明一个临时缓冲区path[4096]。只要路径名不太长,这就可以工作。如果路径太长,那么最安全的选择是打印错误而不是继续。

对于".""..",您可以声明

const char *temp1 = ".";
const char *temp2 = "..";

这样可以避免意外地写入temp1temp2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>

void read_sub(char *subdir)
{
    DIR *dirp = opendir(subdir);
    if (!dirp)
        return;

    struct dirent *dentry;
    while ((dentry = readdir(dirp)) != 0)
    {
        if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
            continue;

        printf("%s/", subdir);

        char path[4096];
        int len = strlen(subdir) + 1 + strlen(dentry->d_name) + 1;
        if (len >= sizeof(path)) 
        {
            printf("path is too long...\n");
            break;
        }
        sprintf(path, "%s/%s", subdir, dentry->d_name);

        struct stat st;
        stat(path, &st);
        if (S_ISDIR(st.st_mode))
        {
            printf("%s\n", dentry->d_name);
            read_sub(path);
        }
        else
        {
            printf("%s\n",dentry->d_name);
        }
    }

    closedir(dirp);
}

或者,您可以为path

使用可变长度数组
int len = strlen(subdir) + 1 + strlen(dentry->d_name) + 1;
char path[len];
sprintf(path, "%s/%s", subdir, dentry->d_name);