C++ 在linux上运行的opendir()在名称和空格上失败
我的程序探索当前目录和所有子目录以打印所有文件名。但是,当目录名称中有空格时,它会产生分段错误。这只发生在linux-windows上,工作正常 名称存储在C++ 在linux上运行的opendir()在名称和空格上失败,c++,linux,directory,io,C++,Linux,Directory,Io,我的程序探索当前目录和所有子目录以打印所有文件名。但是,当目录名称中有空格时,它会产生分段错误。这只发生在linux-windows上,工作正常 名称存储在dirent.d_name中,它是字符[256]。我尝试过使用它,使用c_str()将其转换为c字符串,我尝试过将目录名编码为代码,我尝试过转义空间(尽管我认为我做得不正确) 如果将DIR*指针和struct dirent*指针作为参数传递,而不是简单地形成并传递下一个打开路径,则会遇到问题。您希望在递归函数本身中处理目录的打开,而不是作为从
dirent.d_name
中,它是字符[256]
。我尝试过使用它,使用c_str()
将其转换为c字符串,我尝试过将目录名编码为代码,我尝试过转义空间(尽管我认为我做得不正确)
如果将
DIR*
指针和struct dirent*
指针作为参数传递,而不是简单地形成并传递下一个打开路径,则会遇到问题。您希望在递归函数本身中处理目录的打开,而不是作为从main()
传递的单个指针,例如
void print_dir_rec(const char *name)
{
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(name)))
return;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_DIR) {
char path[1024];
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
printf("[%s]\n", entry->d_name);
print_dir_rec(path);
}
}
closedir(dir);
}
(注意:您可以根据需要或使用path\u MAX
宏来调整为path
提供的字符数)
这样,就不会有单个指针在每次递归调用中被重用,从而导致问题。列出当前目录下所有目录的简短示例可以是:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
void print_dir_rec(const char *name)
{
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(name)))
return;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_DIR) {
char path[1024];
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
printf("[%s]\n", entry->d_name);
print_dir_rec(path);
}
}
closedir(dir);
}
int main(void) {
print_dir_rec(".");
return 0;
}
#包括
#包括
#包括
#包括
#包括
无效打印目录记录(常量字符*名称)
{
DIR*DIR;
结构方向*条目;
如果(!(dir=opendir(name)))
回来
while((entry=readdir(dir))!=NULL){
如果(条目->数据类型==DT\U目录){
字符路径[1024];
如果(strcmp(条目->数据单元名称,“.”)=0 | | strcmp(条目->数据单元名称,“…”)==0)
持续
snprintf(路径,sizeof(路径),%s/%s”,名称,条目->d_名称);
printf(“[%s]\n”,条目->数据单元名称);
打印目录记录(路径);
}
}
closedir(dir);
}
内部主(空){
打印目录记录(“.”);
返回0;
}
看看开场白和阅读是如何处理的,需要传递哪些信息。通过在每个递归调用中为path
提供存储,您可以保证名称在递归调用返回之前保持在范围内
如果您还有其他问题,请告诉我。
dname
是属于readdir
的存储(可能会被重新使用),您可以从中复制以将名称保存在其他存储中,但您不能对dname
成员本身进行任何转换或操作,它只是被下一个名称覆盖。我的意思是,我尝试从dname构造一个字符串,然后传递string.c_str()而不是dname。通常,您希望存储在整个递归调用的范围内,例如char path[1024]
,然后使用snprintf
创建路径,例如,使用name
中的当前目录,您可以使用snprintf(路径,大小(路径),“%s/%s”,名称,条目->d_名称)
No让你的函数用一个const char*
代替DIR*DIR
,例如,print\u DIR\u rec(const char*name)
并进行递归调用print\u DIR\u rec(path)
。完成后你永远不会调用closedir()
。如果你能使用C++17,这会变得非常简单。C++的旧版本也有BooS.FooScript版本,非常感谢它的完美工作!你能在snprintf()上展开一点吗?它到底是做什么的?为什么有必要?(对不起,我得去接孩子),sprintf
在这种情况下允许您将格式化字符串写入缓冲区(path
)。为了将新目录与当前路径相结合,必须在它们之间放置目录分隔符。这就是sprintf
(或上面使用的snprintf
)发挥作用的地方。格式字符串“%s/%s”
允许您将'/'
放置在两个字符串之间,将新的目录名添加到当前路径的末尾。在C++中,你可以用<代码> STD::String 来简单地连接字符串。(尽管具有自动存储持续时间的固定阵列效率更高)
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
void print_dir_rec(const char *name)
{
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(name)))
return;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_DIR) {
char path[1024];
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
printf("[%s]\n", entry->d_name);
print_dir_rec(path);
}
}
closedir(dir);
}
int main(void) {
print_dir_rec(".");
return 0;
}