os.mkdirall是创建多级目录的唯一稳妥选择,因其逐级创建缺失父目录、幂等返回nil;而os.mkdir仅建最后一级,父目录缺失即报“no such file or directory”。

用 os.MkdirAll 创建目录是唯一稳妥的选择,别碰 os.Mkdir —— 它只建最后一层,路径里缺个父目录就直接报 "no such file or directory"。
为什么 os.MkdirAll 必须是默认操作
它会逐级检查并创建缺失的上级目录,比如传入 "logs/error/2024/06",自动补上 logs、logs/error、logs/error/2024;而 os.Mkdir 遇到 logs/error 这一级不存在,就立刻失败。
- 返回
nil表示“路径已存在”或“成功创建”,不是错误 - 对已存在目录不做权限校验(Go 1.19+),所以别指望它帮你发现权限不对
- 并发调用不安全:多个 goroutine 同时执行
os.MkdirAll("a/b/c", 0o755)可能触发竞态,尤其在慢磁盘或 NFS 上
os.MkdirAll 的权限参数怎么写才不翻车
第二个参数是 os.FileMode,必须用八进制字面量,写成 0o755(Go 1.13+ 推荐)或 0755;写成 755 就是十进制,实际权限变成 01157(八进制),目录可能不可遍历。
- Linux/macOS 上权限受进程
umask影响,比如umask=0022时传0o777,最终得到的是0o755 - Windows 忽略权限位,传什么都一样,但字段仍会被保留(不影响功能)
- 生产环境建议固定用
0o755:目录可进入(x)、所有者可写(w)、组和其他人只读
路径处理和错误判断的实操要点
路径来自用户输入或配置时,必须先 filepath.Clean(),否则可能被 ../ 跳出预期范围;错误不能只看 err != nil,得用标准判断函数区分类型。
- 用
filepath.Clean("data/../cache/")→"cache",避免越权写入 - 路径末尾别带斜杠,比如
"logs/",某些挂载点下行为异常 - 正确判断:
if err != nil && !os.IsExist(err),再根据需要处理os.IsPermission(err)或os.IsNotExist(err) - 别用
strings.Contains(err.Error(), "file exists")做判断,不可靠且易破
组合场景:先建目录再写文件的惯用写法
这是日志、缓存、导出等场景最常踩坑的地方——os.Create 不会建父目录,必须手动补全。
- 提取目录:
dir := filepath.Dir("output/reports/report.json")→"output/reports" - 建目录:
os.MkdirAll(dir, 0o755),记得检查!os.IsExist(err) - 再创建文件:
f, err := os.Create("output/reports/report.json"),此时父目录已确保存在 - 符号链接路径要小心:
os.MkdirAll默认按软链目标解析,不是按路径字符串本身;想严格按字面创建,得自己os.Lstat+ 拆解路径
真正容易忽略的是三件事:路径是否 clean 过、权限字面量是不是八进制、错误是否做了类型判别。线上跑几天才暴露的问题,往往就卡在这三处。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











