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

Getting full file path during recursive file walk C

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

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

这是我的代码:

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

递归是一种简洁的表达方式(尤其是遍历目录),但实际上在实践中通常应该避免使用它。如果目录树足够深,它会使您的软件崩溃。

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

我将用于处理目录树的代码包含在 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] = '[=11=]';

  return d;
}

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

你的代码中有很多小问题。

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

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

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

  • 修复 printf 的格式
  • recursiveWalk
  • 中删除未使用的 fullPath 参数
  • 总是计算path并在文件分支
  • 中使用它
  • 注释掉不需要的path[len] = '[=22=]'
  • 我还将 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;
}