在递归文件遍历 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] = 0
当 snprintf
保证但是缓冲区是 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;
}
我正在递归遍历目录以更改文件。我的更改文件功能需要文件的完整路径才能执行操作。但是,我的程序现在正在做的只是获取当前文件或文件夹的名称,而不是完整路径。
我的方法是创建一个字符串并不断向其添加名称,直到获得完整路径。但是,因为我正在进行递归,所以我在传递字符串以向其附加更多字符串时遇到了麻烦。
这是我的代码:
#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
中使用或更改 - 您的格式很奇怪:您使用
level*2
来限制从空字符串打印的字符数 - 你只有在找到目录时才计算实际路径,而你说你需要它来更改文件。
- 你在
snprintf
之后添加path[len] = 0
当snprintf
保证但是缓冲区是 null 终止的
fullPath
但除此之外,您正确地将分析目录的路径附加到初始调用中传递的路径,但在 pathName
变量中,并计算为 path
.
因此,您的代码可能的修复方法是:
- 修复 printf 的格式
- 从
recursiveWalk
中删除未使用的 - 总是计算
path
并在文件分支 中使用它
- 注释掉不需要的
path[len] = '[=22=]'
- 我还将
while (entry = readdir(dir));
替换为while ((entry = readdir(dir)));
以明确告诉编译器我想设置条目然后测试它的值 - 并删除警告
fullPath
参数
可能的代码:
#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;
}