【发布时间】:2011-06-22 09:07:32
【问题描述】:
我是 C 新手,我试图从当前工作目录中递归所有目录/文件并输出它们的信息。我遇到的问题是我想不出一个好的解决方法是,当同一目录中有两个文件夹时,路径第二次构建错误。例如,如果在“/something/dir1”完成后 dir1 和 dir2 在同一路径中,则路径应该变为“/something/dir2”,但由于我写东西的方式而变为“/something/dir1/dir2”。我想只跟踪以前的路径,但如果不不断地在每次递归调用中重写它,我不确定是否有办法做到这一点。
更新:我已经修复了原来的错误,并认为我会在这里发布我的新代码。我不知道的技巧是 opendir(".") 和 changedir("..") 实际上会将周期转换为当前或以前的完整路径。至于将 type = 8 和 type = 4 语句更改为更具可读性的 S_ISDIR(statbuf.st_mode) 和 S_ISREG(statbuf.st_mode) 语句,它们似乎根本不起作用,而 type 语句则起作用。不确定语法和我尝试使用它们的方式有什么问题。
更新 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);
}
}
【问题讨论】:
-
您似乎已经回答了自己的问题...
-
@Oli:重读。 OP 说当前代码中存在错误。此外,这将是一个非常有用的学习练习,用于学习如何在可能的情况下最好地在每个递归级别重用现有缓冲区,而不是在堆上(或更糟糕的是,在堆栈上)分配大量内存。
-
type == 8?readdir联机帮助页中的符号常量是有原因的。 -
抱歉,我说错了。
stat联机帮助页。特别是你应该使用S_ISDIR(statbuf.st_mode)来确定某个东西是否是一个目录。 -
使用
d_type(如果可用)而不是调用stat可以使目录遍历速度提高几个数量级。