os.Mkdir 只能创建单层目录且父目录必须存在,否则报错;os.MkdirAll 递归创建所有缺失目录,已存在时静默成功,是绝大多数场景的首选。
调用 os.Mkdir 时,如果指定路径中的上级目录(如 /tmp/a/b 中的 /tmp/a)不存在,函数会直接返回 no such file or directory 错误。它不会自动创建中间路径,这是和 mkdir -p 的关键区别。
perm 仅控制新建目录本身的权限位(如 0755),不改变父目录权限os.Mkdir 仍会返回 file exists 错误(不是成功)绝大多数实际场景应优先使用 os.MkdirAll:它会递归创建所有缺失的父目录,并在目标目录已存在时静默成功(不报错)。
mkdir -p
perm 参数,但该权限仅应用于**最深层新建的目录**;中间路径使用系统默认 umask 衍生权限(通常为 0755)nil 表示路径已存在或成功创建;非 nil 错误才需处理err := os.MkdirAll("/tmp/a/b/c", 0755)
if err != nil {
log.Fatal(err) // 仅当磁盘满、权限不足等真正失败时触发
}
perm 不是“最终目录权限”,而是传给底层 mkdir(2) 系统调用的 mode 值,受进程 umask 影响。例如进程 umask 为 0022,即使传入 0777,实际创建的目录权限也是 0755。
os.MkdirAll 后用 os.Chmod 显式设置umask(0)(需 cgo 或 syscall,不推荐)0755 而非 0777,避免过度开放在 Windows 上,os.MkdirAll("C:\a\b", 0755) 因反斜杠转义问题会失败。必须用正斜杠或双反斜杠:
"C:/a/b" 或 `C:\\a\\b`
perm 参数(除只读标志外),0755 和 0600 效果相同filepath.Join("C:", "a", "b") 构造路径path := filepath.Join("tmp", "data", "logs")
err := os.MkdirAll(path, 0755) // 自动适配 / 或 \
实际项目中,几乎不需要直接调用 os.Mkdir;os.MkdirAll 覆盖了 99% 的需求,而它的错误语义更清晰、行为更可预
测。唯一需要 os.Mkdir 的场景,是明确要拒绝父目录自动创建——比如校验配置路径是否严格按预期结构存在。