在递归文件遍历C期间获取完整文件路径

时间:2015-08-02 05:21:54

标签: c recursion string-concatenation

我正在通过目录进行递归遍历来更改文件。我的更改文件功能需要文件的完整路径才能执行操作。但是,我的程序现在正在做的只是获取当前文件或文件夹的名称,而不是完整路径。

我的方法是,我会创建一个字符串并继续为其添加名称,直到我获得完整路径。但是,因为我正在进行递归,所以我遇到麻烦传递字符串以附加更多字符串。

这是我的代码:

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

void recursiveWalk(const char *pathName, char *fullPath, int level) {
   DIR *dir;
   struct dirent *entry;

   if (!(dir = opendir(pathName))) {
      fprintf(stderr, "Could not open directory\n");
      return;
   }

   if (!(entry = readdir(dir))) {
      fprintf(stderr, "Could not read directory\n");
      return;
   }

   do {
      if (entry->d_type == DT_DIR) { // found subdirectory
         char path[1024];

         int len = snprintf(path, sizeof(path)-1, "%s/%s", pathName, entry->d_name); // get depth
         path[len] = 0;

         // skip hidden paths
         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
         }

         fprintf(stdout, "%*s[%s]\n", level*2, "", entry->d_name);

         // Append fullPath to entry->d_name here

         recursiveWalk(path, fullPath, level + 1);
      }
      else { // files
         fprintf(stdout, "%*s- %s\n", level*2, "", entry->d_name);

         //changeFile(fullPath);
      }
   } while (entry = readdir(dir));

   closedir(dir);
}

int main(int argn, char *argv[]) {
   int level = 0;
   recursiveWalk(".", "", level);

   return 0;
}

2 个答案:

答案 0 :(得分:1)

递归是表达事物(特别是步行目录)的简洁方式,但实际上你通常应该在实践中避免使用它。如果目录树足够深,它将使您的软件崩溃。

使用队列消除了递归的需要,并且通常是一种有效的遍历方式。

我在project ...

中包含了用于处理目录树的代码
static int on_dir(const char* const dir, struct duplicate** dp) {
  bool r = opts.recurse;

  DIR* d = opendir(dir); 

  if (!d)
    return - 1;

  struct dirent* de;

  while ((de = readdir(d))) {

    struct stat s;

    size_t bs = strlen(dir) + strlen(de->d_name) + 2;
    char b[bs];

    const char* const a = strjoin(b, dir, de->d_name, '/');

    if (lstat(a, &s)) {

      print_error("unable to stat %s", d);
      continue;
    }

    if (S_ISREG(s.st_mode))
      if (on_file(a, &s, dp))
        print_error("unable to process file %s/%s", dir, de->d_name);
  }

  if (!r) {

    if (closedir(d))
      on_fatal("unable to close directory %s", dir);

    return 0;
  }

  rewinddir(d);

  while ((de = readdir(d))) {

    struct stat ds;

    size_t bs = strlen(dir) + strlen(de->d_name) + 2;
    char b[bs];

    const char* const d = strjoin(b, dir, de->d_name, '/');

    if (lstat(d, &ds)) {

      print_error("unable to stat %s", d);
      continue;
    }

    if (S_ISDIR(ds.st_mode)) {

      const char* const dot = ".";
      const char* const dotdot = "..";

      if (!strcmp(dot, de->d_name) || !strcmp(dotdot, de->d_name))
        continue;

      struct path* p = path_create(strcpy(fmalloc(bs), d));

      queue_add(&paths, &p->queue);
    }
  }

  if (closedir(d))
    print_error("unable to close directory %s", dir);

  return 0;
}

以及strjoin

的代码
static inline char* strjoin(char* restrict const d, const char* restrict const a, const char* restrict const b, const char c) {
  size_t na = strlen(a);
  size_t nb = strlen(b);

  memcpy(d, a, na);
  d[na] = c;
  memcpy(d + na + 1, b, nb);

  d[na + nb + 1] = '\0';

  return d;
}

我希望这会有所帮助。请随意使用您在git存储库中找到的任何代码。

答案 1 :(得分:1)

您的代码中存在许多小问题。

  • 您永远不会在fullPath
  • 中使用或更改recursiveWalk
  • 您的格式很奇怪:您使用level*2来限制从空字符串打印的字符数
  • 只有在找到目录时才计算实际路径,而您说需要它来更改文件。
  • path[len] = 0 snprintf之后添加snprintf pathName保证缓冲区为空终止

但除此之外,您正确地将路径传递给分析的目录附加到初始调用中传递的路径,但是在path变量中,并计算为fullPath

因此,您的代码的可能修复方法是:

  • 修复printf的格式
  • recursiveWalk
  • 中删除未使用的path参数
  • 始终计算path[len] = '\0'并在文件分支
  • 中使用它
  • 注释掉不必要的while (entry = readdir(dir));
  • 我还用while ((entry = readdir(dir)));替换#include <stdio.h> #include <stdlib.h> #include <regex.h> #include <string.h> #include <dirent.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> void recursiveWalk(const char *pathName, int level) { DIR *dir; struct dirent *entry; if (!(dir = opendir(pathName))) { fprintf(stderr, "Could not open directory\n"); return; } if (!(entry = readdir(dir))) { fprintf(stderr, "Could not read directory\n"); return; } do { char path[1024]; int len = snprintf(path, sizeof(path)-1, "%s/%s", pathName, entry->d_name); // get depth // path[len] = 0; if (entry->d_type == DT_DIR) { // found subdirectory // skip hidden paths if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } fprintf(stdout, "%s [%s] (%d)\n", pathName, entry->d_name, level); // Append fullPath to entry->d_name here recursiveWalk(path, level + 1); } else { // files fprintf(stdout, "%s (%d)\n", path, level); //changeFile(fullPath); } } while ((entry = readdir(dir))); closedir(dir); } int main(int argn, char *argv[]) { int level = 0; recursiveWalk(".", level); return 0; } 以明确告诉编译器我想设置条目然后测试其值 - 并删除警告

可能的代码:

{{1}}