C++create_directories递归创建

2026-04-11 03:25:28 986阅读 0评论

create_directories:C++17里那个“不声不响就把整棵树搭好的人”

上周帮同事修一段构建日志路径的代码,他写了三层 if (!exists(p)) create_directory(p) 嵌套,还手动拼 parent_path()。我顺手换成一行 create_directories(p),他盯着控制台看了三秒:“这……就完了?连中间那几层空目录都不用管?”

是的,std::filesystem::create_directories 就是干这个的——它不挑食、不抱怨、不卡在半路,只要路径合法,从根到叶一气呵成。

但别急着抄代码。很多人用完发现“为啥有些目录没建出来?”“报错说权限不够,可我明明有写权限?”——问题往往不出在函数本身,而出在我们对它的隐含契约理解得不够细。


它真能“递归”?先看清什么叫“递归创建”

create_directories 的“递归”,不是自己一层层调自己,而是按路径分段解析,逐级检查并创建缺失环节。比如传入 "a/b/c/d"

  • 先看 a 存不存在?不存在 → 创建;
  • 再看 a/b 存不存在?不存在 → 创建;
  • 接着 a/b/c → 创建;
  • 最后 a/b/c/d → 创建。

关键点来了:它只创建“目录”,绝不碰文件。
如果 a/b/c 已经是个普通文件(不是目录),它不会报错退出,而是直接失败——因为 a/b/c/d 无法在文件下面再建子目录。这点和 mkdir -p 行为一致,但比很多人的直觉更“较真”。


常见翻车现场,和怎么绕开

❌ 场景一:路径末尾带斜杠,却意外指向文件

path p = "logs/2024/06/";
create_directories(p); // 看似没问题?

但如果 logs/2024/06 实际上是个已存在的普通文件(比如某次误写日志时生成的),create_directories 会静默失败(返回 false),而你可能根本没检查返回值。

✅ 解决:永远检查返回值,且必要时加诊断逻辑

if (!create_directories(p)) {
    if (exists(p) && !is_directory(p)) {
        throw std::runtime_error("Path exists but is not a directory: " + p.string());
    }
    throw std::runtime_error("Failed to create directories: " + p.string());
}

❌ 场景二:相对路径撞上当前工作目录的“隐形墙”

// 当前工作目录是 /home/user/project
create_directories("../output/cache"); // 试图建到项目外

这行代码可能成功,也可能失败——取决于你有没有权限写上级目录。更麻烦的是,错误信息只报 permission denied,不告诉你具体卡在哪一级

✅ 解决:absolute() 锚定起点,把模糊变明确

path abs_p = absolute(p); // 转成绝对路径
if (!create_directories(abs_p)) {
    // 此时错误定位清晰:就是 abs_p 这条路走不通
}

❌ 场景三:跨文件系统符号链接,它认怂

假设 a 是个软链,指向另一块磁盘上的 /mnt/data,而你调用 create_directories("a/b/c")
create_directories 默认不解析符号链接follow_symlinksfalse),它会尝试在 a 所在位置建 b,而不是在 /mnt/data 下建——结果大概率失败。

✅ 解决:明确意图,需要穿透就自己处理

// 如果你确定要穿透软链,得手动 resolve
path resolved = weakly_canonical(p); // 会尝试解析,失败也不抛异常
create_directories(resolved);

一个小而实的技巧:批量创建时别重复造轮子

有人习惯对每个子路径都调一次 create_directories

create_directories("build");
create_directories("build/obj");
create_directories("build/bin");
create_directories("build/logs");

其实完全没必要。只要最深的那个路径建成了,上面所有父级必然存在
所以这一组调用,完全可以精简为:

create_directories("build/logs"); // 自动搞定 build, build/obj, build/bin

前提是你的目录结构是树状嵌套的——这恰恰是绝大多数构建场景的真实形态。


最后一句实在话

create_directories 不是什么黑科技,它只是把“检查→创建→继续”这个重复动作封装得足够干净。
但它真正的价值,不是省了三行代码,而是把“路径可靠性”这件事,从易出错的手动流程,变成一个可验证、可测试、可交付的原子操作

下次再看到日志目录报错,别急着加 system("mkdir -p ...")
先确认路径是否绝对、是否被文件占位、返回值有没有被忽略——往往问题就出在这三步里。

毕竟,工具再好,也得有人读懂它的脾气。

文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
验证码
评论列表 (暂无评论,986人围观)

还没有评论,来说两句吧...

目录[+]