在C中递归目录

时间:2011-02-06 19:24:42

标签: c recursion directory

我是C的新手并试图从当前工作目录中递归所有目录/文件并输出他们的信息。我遇到的问题是我想不出一个好的方法来解决,当同一目录中有两个文件夹时,第二次路径构建错误。例如,如果dir1和dir2在“/ something / dir1”完成后处于相同的路径中,则路径应该变为“/ something / dir2”,但由于我编写的东西的方式变为“/ something / dir1 / dir2”。我想只是跟踪前面的路径,但是如果不经常在每次递归调用时重写它,我都不知道如何做到这一点。

更新:我已经解决了原来的错误,并认为我会在这里发布我的新代码。我不知道的诀窍是opendir(“。”)和changedir(“..”)实际上将句点转换为完整的当前路径或上一个路径。至于将type = 8和type = 4语句更改为更易读的S_ISDIR(statbuf.st_mode)和S_ISREG(statbuf.st_mode)语句,它们似乎在类型语句执行时根本不起作用。不确定语法和我尝试使用它们的方式有什么问题。

更新2:我在这里解决了S_ISDIR / S_ISREG问题 - How to use S_ISREG() and S_ISDIR() POSIX Macros?

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

void helper(DIR *, struct dirent *, struct stat, char *, int);
void dircheck(DIR *, struct dirent *, struct stat, char *, int);

int main(int argc, char *argv[]){

  DIR *dip;
  struct dirent *dit;
  struct stat statbuf;
  char currentPath[FILENAME_MAX];
  int depth = 0; /*Used to correctly space output*/

  dip = opendir(".");
  getcwd(currentPath, FILENAME_MAX);

  while((dit = readdir(dip)) != NULL){

    /*Skips . and ..*/
    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
      continue;

    stat(currentPath, &statbuf);

    /*Checks if current item is of the type file (type 8)*/
    if(dit->d_type == 8)
      printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);

    /*Checks if current item is of the type directory (type 4)*/
    if(dit->d_type == 4)
      dircheck(dip, dit, statbuf, currentPath, depth);

  }
  return 0;
}

/*Recursively called helper function*/
void helper(DIR *dip, struct dirent *dit, struct stat statbuf, char currentPath[FILENAME_MAX], int depth){
  int i = 0;
  dip = opendir(currentPath);

  while((dit = readdir(dip)) != NULL){

    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
      continue;

    stat(currentPath, &statbuf);

    if(dit->d_type == 8){
      for(i = 0; i < depth; i++)
        printf("    ");
      printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
    }

    if(dit->d_type == 4)
      dircheck(dip, dit, statbuf, currentPath, depth);

  }
}

void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf, char currentPath[FILENAME_MAX], int depth){
  int i = 0;

  strcat(currentPath, "/");
  strcat(currentPath, dit->d_name);

  /*If two directories exist at the same levelt the path
    is built wrong and needs to be corrected*/
  if((chdir(currentPath)) == -1){
    chdir("..");
    getcwd(currentPath, FILENAME_MAX);
    strcat(currentPath, "/");
    strcat(currentPath, dit->d_name);

    for(i = 0; i < depth; i++)
      printf ("    ");
    printf("%s (subdirectory)\n", dit->d_name);
    depth++;
    helper(dip, dit, statbuf, currentPath, depth);
  }

  else{
    for(i =0; i < depth; i++)
      printf("    ");
    printf("%s (subdirectory)\n", dit->d_name);
    chdir(currentPath);
    depth++;
    helper(dip, dit, statbuf, currentPath, depth);
  }

}

2 个答案:

答案 0 :(得分:4)

不要不必要地重新发明轮子。如果您使用的是unixy系统,nftw库函数(POSIX中的XSI选项组的一部分,意味着它几乎普遍可用)可以完全满足您的需求:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/nftw.html

另一方面,如果您将此作为学习练习,或者您有({1}}不适合您需要的(适度罕见)实例(例如,如果您需要执行此操作)同时从多个线程进行目录递归)继续调试您的解决方案。

答案 1 :(得分:1)

我要做的第一件事就是改变这一点:

if(type == 4)

对此:

if(S_ISDIR(statbuf.st_mode))

有关详细信息,请参阅stat manpage

其次,看起来你永远不会打电话给closedir。你需要释放东西。

第三......不要在两个地方复制粘贴opendir / readdir代码,将这些冗余工作放在同一个函数中是很有价值的。

最后..在每次递归时在堆栈上分配MAX_PATH会变得相当大。您可能需要考虑使用mallocrealloc。但正如上面提到的@R ..,你应该尝试尽可能地重复使用这些缓冲区。对于大型目录树,这将占用大量空间并且价格昂贵。