我遇到了一个编程问题,希望有人可以帮助我。我正在尝试为工作中的任务学习C编程,我为自己设置了一个小项目,其中包括读取包含所有子目录的文件树,以获取有关每个文件的信息。
我得到的问题是我的程序不会忽略目录路径以/结尾。或者/ ..当它打印所有目录时,我想在子目录前面留出空间以获得可读性。
所以错误发生在这个部分:
int isDir(const char *parent, char *name) {
struct stat st_buf; // file info
char buf[BUF_SIZE];
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
return 0;
}
char *path = malloc(strlen(name) + strlen(parent) + 2);
//sprintf(char *buf, const char *format, [arg1],[arg2],...)
sprintf(path, "%s/%s", parent, name);
stat(path, &st_buf); //
return S_ISDIR(st_buf.st_mode); //directory
}
这是主要和列表功能:
int list(const char *name) {
DIR *dirp = opendir(name);
struct dirent *dentry;
char buf[BUF_SIZE];
while ((dentry = readdir(dirp)) != NULL) {
char *dir_name = dentry->d_name;
printf(" %s\n", dir_name);
//if it's dir, then go into dir
if (isDir(name, dir_name)) { //name : parent, dir_name : child
chdir(dir_name);
getcwd(buf, BUF_SIZE);
list(buf);
}
}
closedir(dirp);
}
int main()
{
list(".");
return 0;
}
结果如下:
hm1.c Data lab1.txt result1 lab3.txt . .. . .. result2 lab3.txt . .. result3 lab3.txt . .. a.c . .. a.out
结果我想打印
hm1.c Data lab1.txt result1 lab3.txt result2 lab3.txt result3 lab3.txt a.c a.out
答案 0 :(得分:1)
如果您isDir
oe .
然后..
的真/假值,则S_ISDIR
返回true / false,返回false(或零)其他案件
你真正需要的是返回3个值SKIP,isFILE或isDIR中的一个的函数,然后根据它写出你的打印逻辑。
您还需要修复内存泄漏
另请注意,chdir(dir_name);
会更改进程的实际目录,因此一旦从循环中的list
返回,您将无法再打开正在循环的文件或目录(因为你现在在不同的目录中)
这将解决您的问题并打印您想要的格式
enum { doSkip, isFile, isDir } testDir(char *path, char *name)
{
struct stat st_buf;
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
return doSkip;
}
stat(path, &st_buf);
if (S_ISDIR(st_buf.st_mode))
return isDir;
return isFile;
}
void list(const char *path, int indentlevel)
{
DIR *dirp = opendir(path);
struct dirent *dentry;
char buf[10000]; // Lets just make the buffer sufficently big for this example
if (!dirp) {
printf("%*sNo access\n",indentlevel,"");
return;
}
while ((dentry = readdir(dirp)) != NULL) {
sprintf(buf,"%s/%s", path, dentry->d_name);
switch (testDir(buf,dentry->d_name)) {
case doSkip:
/* do nothing */
break;
case isDir:
printf("%*s%s:\n",indentlevel,"",dentry->d_name);
list(buf,indentlevel+4);
break;
case isFile:
printf("%*s%s\n",indentlevel,"",dentry->d_name);
break;
}
}
closedir(dirp);
}
int main()
{
list(".", 0);
return 0;
}
答案 1 :(得分:0)
如果您愿意使用C ++,另一种方法是使用std::experimental::filesystem
,也(通常)称为Boost.Filesystem。有了这个,你会做类似的事情:
#include <experimental/filesystem> // Could substitute <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
using namespace std::experimental;
int main(int argc, char *argv[])
{
const auto path = filesystem::path{ argc > 1 ? argv[1] : "." };
if( filesystem::is_directory(path) )
{
std::cout << path << " is a directory containing:\n";
for( const auto& entry : boost::make_iterator_range( filesystem::recursive_directory_iterator{path}, {} ) )
{
std::cout << entry << "\n";
}
}
}
看到它运行here。请注意,目录迭代器会自动跳过.
和..
。