c++标准库直到c++20才原生支持递归创建多级目录;c++17引入std::filesystem::create_directories但需手动检查返回值,且不处理权限、磁盘满等失败场景。

mkdir 多级目录失败:C++ 标准库不支持递归创建
标准 C++(直到 C++20)的 std::filesystem::create_directories 才原生支持递归建目录;C++17 虽引入了 std::filesystem,但部分编译器默认未启用,或旧项目仍用 POSIX/C 风格写法。直接调用 mkdir("a/b/c", 0755) 在路径中任一上级不存在时会失败,并返回 -1,errno 设为 ENOENT。
常见错误现象:mkdir: No such file or directory,但你明明写了完整路径 —— 因为它只建最后一级。
- 必须手动拆解路径,逐级检查并创建(C++17 前主流做法)
- C++17 启用
std::filesystem后,优先用std::filesystem::create_directories,它自动跳过已存在目录,且返回true表示“至少有一级被新建” - 注意 Windows 路径分隔符:用
/或\均可,但std::filesystem内部统一处理;避免硬编码"\"拼接
std::filesystem::create_directories 的实际调用要点
它不是“保证路径存在”的银弹 —— 它只负责建目录,不处理权限、磁盘满、只读挂载等失败场景。调用后必须检查返回值,不能假设成功。
典型使用场景:打开文件前确保父目录就位,比如写日志到 "log/2024/06/app.log"。
- 路径字符串建议用
std::filesystem::path构造,避免手动字符串切分出错 - 传入相对路径时,行为依赖当前工作目录(
getcwd),生产环境建议用绝对路径或显式拼接基路径 - 若父目录存在但无写权限,函数返回
false,errno可能是EACCES,需捕获异常或检查std::filesystem::status
示例:
std::filesystem::path p = "log/2024/06";
if (!std::filesystem::create_directories(p)) {
// 创建失败:可能已存在(OK),也可能权限不足或磁盘错误
if (!std::filesystem::exists(p)) {
throw std::runtime_error("Failed to create dir: " + p.string());
}
}
Windows 下 _mkdir 与 mkdir 兼容性陷阱
MSVC 默认不认 POSIX 的 mkdir,而用 _mkdir(单级)或 _wmkdir(宽字符)。混用头文件(如同时包含 <sys></sys> 和 <direct.h></direct.h>)可能引发隐式声明警告或链接失败。
- 跨平台项目别直接写
_mkdir;统一走std::filesystem或封装一层适配函数 - MinGW 环境下可用 POSIX
mkdir,但依然不支持递归,需自行循环调用 - 调用
_mkdir前务必用std::filesystem::exists或GetFileAttributes检查上级是否存在,否则静默失败
写入文件前的最小安全检查链
自动建目录只是第一步。真正容易被忽略的是:建完目录后立即 open/write,仍可能失败 —— 因为目录创建和文件写入之间存在竞态窗口(尤其 NFS 或容器挂载卷),且目录权限未必允许后续文件写入。
- 建目录后,用
std::filesystem::status(p).permissions()检查是否含owner_write(或至少owner_read | owner_exec,因为目录需执行权限才能 cd 进入) - 打开文件时用
std::ofstream f(path, std::ios::out | std::ios::app),不要省略std::ios::out;否则某些文件系统在只读目录下可能报Permission denied而非更明确的错误 - 如果路径含时间戳或动态生成(如
"tmp/" + uuid + ".bin"),建议先建好固定父目录(如"tmp/"),再生成文件名,避免每次重复建目录
事情说清了就结束
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











