
在 go 中,使用 `os.mkdirall(path, perm)` 可以简洁、安全、跨平台地递归创建嵌套目录,若路径已存在则静默成功,完全符合 `-p` 语义。
Go 标准库提供了高度惯用且健壮的解决方案:os.MkdirAll。它正是为满足“递归创建 + 存在即忽略”这一常见需求而设计,语义上等价于 Bash 的 mkdir -p、C# 的 Directory.CreateDirectory、PHP 的 mkdir(..., ..., true) 或 Java 的 File.mkdirs()。
基本用法
package main
import (
"fmt"
"os"
)
func main() {
path := "some/deep/nested/path"
err := os.MkdirAll(path, 0755) // Unix 权限;Windows 仅保留读/写位
if err != nil {
fmt.Printf("创建目录失败: %v\n", err)
return
}
fmt.Println("目录(含父级)创建成功或已存在")
}✅ 关键特性说明:
- 自动逐级创建缺失的父目录(如 some/ → some/deep/ → …);
- 若目标路径已是目录(无论是否由本次调用创建),直接返回 nil,无副作用、不报错;
- 所有新建目录均使用统一权限 perm(注意:在 Windows 上权限位会被忽略,仅影响文件系统支持的属性);
- 线程安全,可被并发调用(但需注意竞态下多个 goroutine 同时创建同一路径时,仅一个会真正执行 mkdir,其余静默通过)。
注意事项与最佳实践
- 权限设置建议:生产环境推荐显式使用八进制字面量(如 0755),避免十进制误写;若需最大兼容性,可结合 os.FileMode(0755)。
- 错误处理不可省略:虽然存在时静默,但磁盘满、权限不足、路径含非法字符等仍会返回具体错误,务必检查 err。
- 非原子性说明:MkdirAll 内部是循环调用 os.Mkdir 实现的,并非单个原子系统调用。但在绝大多数场景下,其行为已足够可靠;如需强一致性(如配合文件写入),建议在创建后加一次 os.Stat 验证目标是否为目录。
- 符号链接处理:若路径中某一级是符号链接,MkdirAll 会尝试在其指向的目标位置创建子目录(即遵循链接),行为与大多数 shell 工具一致。
总结
无需封装、无需第三方依赖——os.MkdirAll 就是 Go 生态中创建嵌套目录的标准、惯用、推荐方式。它简洁、明确、跨平台,且与开发者在其他语言中的直觉完全对齐。记住:只要需要 mkdir -p 的能力,就用 os.MkdirAll。










