2016-10-01 57 views
0

我有一个编程问题,希望有人能帮助我。我试图在工作中学习C编程,并为自己设置了一个小项目,其中包括读取包含所有子目录的文件树,以获取有关每个文件的信息。检查目录路径以“。”,“..”结尾

我得到的问题是我的程序不会忽略目录路径以/结尾。或/ ..和当它打印所有的目录时,我想在可读性的子目录前面留出空间。

所以误差在这部分发生:

int isDir(const char *parent, char *name) { 

    struct stat st_buf; // file info 
    char buf[BUF_SIZE]; 

    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 
     return 0; 
    } 
    char *path = malloc(strlen(name) + strlen(parent) + 2); 
    //sprintf(char *buf, const char *format, [arg1],[arg2],...) 
    sprintf(path, "%s/%s", parent, name); 
    stat(path, &st_buf); // 

    return S_ISDIR(st_buf.st_mode); //directory 
} 

而这主要和列表功能:

int list(const char *name) { 
    DIR *dirp = opendir(name); 
    struct dirent *dentry; 
    char buf[BUF_SIZE]; 

    while ((dentry = readdir(dirp)) != NULL) { 
    char *dir_name = dentry->d_name;   

      printf(" %s\n", dir_name); 

     //if it's dir, then go into dir 
     if (isDir(name, dir_name)) { //name : parent, dir_name : child 
      chdir(dir_name); 
      getcwd(buf, BUF_SIZE); 
      list(buf); 
     } 
    } 
    closedir(dirp); 
} 

int main() 
{ 
    list("."); 
    return 0; 
} 

的结果是这样的:

hm1.c 
Data 
lab1.txt 
result1 
lab3.txt 
. 
.. 
. 
.. 
result2 
lab3.txt 
. 
.. 
result3 
lab3.txt 
. 
.. 
a.c 
. 
.. 
a.out 

结果I wan吨至打印

hm1.c 
Data 
    lab1.txt 
    result1 
     lab3.txt 
    result2 
     lab3.txt 
    result3 
     lab3.txt 
a.c 
a.out 
+1

您的'isDir()'函数每次在'name'中调用'.'或'..'以外的内存都会泄漏内存。你也应该至少错误地检查'malloc()'和'opendir()' - 也可以''chdir()'和'getcwd()'。 –

+3

在打印任何内容之前,您需要额外检查'.'和'..',并且您可能需要将其他深度参数传递给'list',以便您可以基于此进行缩进。 –

+0

“printf(”%s \ n“,dir_name)中使用了'dir_name';'defined,set等? 'file_mode'和'my_passwd'变量也不被使用。请参阅制作MCVE([MCVE])的指导原则。他们让人们更容易帮助你。您的代码显示似乎从原来的缩减,但不是最小化和不可验证。 –

回答

1

isDir将返回真/假它返回false(或零),如果你有. OE ..,然后在其他情况下,真/假的S_ISDIR

您真正需要的功能是返回SKIP,isFILE或isDIR三个值中的一个,然后根据此值编写打印逻辑。

您还需要修复您的内存泄漏

还要注意的是chdir(dir_name);改变过程的实际目录,所以一旦你从list你的循环中返回,您将不再能够打开文件或目录,你遍历(因为你现在是在不同的目录)

这将解决您的问题,并打印的格式,你想

enum { doSkip, isFile, isDir } testDir(char *path, char *name) 
{ 
    struct stat st_buf;   
    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 
     return doSkip; 
    } 
    stat(path, &st_buf); 
    if (S_ISDIR(st_buf.st_mode)) 
     return isDir; 
    return isFile; 
} 

void list(const char *path, int indentlevel) 
{ 
    DIR *dirp = opendir(path); 
    struct dirent *dentry; 
    char buf[10000]; // Lets just make the buffer sufficently big for this example 
    if (!dirp) { 
     printf("%*sNo access\n",indentlevel,""); 
     return; 
    } 

    while ((dentry = readdir(dirp)) != NULL) { 

     sprintf(buf,"%s/%s", path, dentry->d_name); 
     switch (testDir(buf,dentry->d_name)) { 
     case doSkip: 
      /* do nothing */ 
      break; 
     case isDir: 
      printf("%*s%s:\n",indentlevel,"",dentry->d_name); 
      list(buf,indentlevel+4); 
      break; 
     case isFile: 
      printf("%*s%s\n",indentlevel,"",dentry->d_name); 
      break; 
     } 
    } 
    closedir(dirp); 
} 

int main() 
{ 
    list(".", 0); 
    return 0; 
} 
0

另一种方式做到这一点,如果你”重新愿意去C++,是使用std::experimental::filesystem,也是(大部分)被称为Boost.Filesystem。有了这个,你会这样做:

#include <experimental/filesystem> // Could substitute <boost/filesystem.hpp> 
#include <boost/range/iterator_range.hpp> 
#include <iostream> 

using namespace std::experimental; 

int main(int argc, char *argv[]) 
{ 
    const auto path = filesystem::path{ argc > 1 ? argv[1] : "." }; 

    if(filesystem::is_directory(path)) 
    { 
     std::cout << path << " is a directory containing:\n"; 

     for(const auto& entry : boost::make_iterator_range(filesystem::recursive_directory_iterator{path}, {})) 
     { 
      std::cout << entry << "\n"; 
     } 
    } 
} 

看到它运行here。请注意,目录迭代器会自动跳过...

+0

你的答案是C++ - OP正在问一个C问题 – Soren

+1

对,这就是为什么我说“如果你愿意去C++”。由于OP已将此任务设置为自己,因此C似乎并不是一项艰难的要求,而且C++具有跨平台,几乎标准的设备来处理它。事实上,它明确依赖于Linux/POSIX功能。我的解决方案不需要,并且需要相当少的代码才能正确维护。 – metal

+0

我想知道如果我可以让你的例子工作来理解递归迭代器的* magic *,并且看看输出是否可以按照规范格式化 - 但是我得到了一个提升链接问题的兔子洞像这样一个http://stackoverflow.com/questions/15634114/cant-link-program-using-boost-filesystem-我必须说,我从来没有一个推动的粉丝,所以即时放弃,而无法做到它运行 – Soren