C++create_directories递归创建
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_symlinks 为 false),它会尝试在 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 ...")。
先确认路径是否绝对、是否被文件占位、返回值有没有被忽略——往往问题就出在这三步里。
毕竟,工具再好,也得有人读懂它的脾气。


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