Go的os包适合底层跨平台文件操作,但处理文本需注意编码、换行符、路径分隔符;推荐用os.ReadFile/WriteFile(小文件)、filepath.Join拼接路径、filepath.WalkDir遍历、os.Stat判断存在性与类型,原子操作依赖os.Rename或os.CreateTemp。

Go 的 os 包适合做底层、跨平台的文件系统操作,但直接用它处理文本内容或结构化数据容易出错——它不自动处理编码、换行符差异或路径分隔符,也不提供原子写入保障。
创建/删除文件和目录用 os.Create、os.MkdirAll、os.Remove
os.Create 总是新建文件(若存在则清空),不支持“仅当不存在时创建”;os.MkdirAll 是安全选择,能递归建多级目录;os.Remove 删除单个文件或空目录,非空目录需用 os.RemoveAll。
- 用
os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)实现“仅新建”,失败时返回*os.PathError,检查Err是否为os.ErrExist -
os.Mkdir("a/b", 0755)在 Linux 下会失败(父目录a不存在),必须改用os.MkdirAll("a/b", 0755) -
os.Remove("nonexistent.txt")返回os.ErrNotExist,不是 panic,要显式判断错误类型而非只看err != nil
读写文件内容优先用 os.ReadFile 和 os.WriteFile
这两个函数是 Go 1.16+ 引入的便捷封装,内部自动处理打开、关闭、错误传播,比手动调 os.Open + io.ReadAll 更简洁。但它们把整个文件加载进内存,不适合大文件。
-
os.ReadFile("config.json")返回[]byte,不是字符串;若需 UTF-8 文本,应后续用string(data)转换,不要假设系统默认编码 -
os.WriteFile("log.txt", []byte("msg\n"), 0644)会覆盖原文件;追加写必须用os.OpenFile配合os.O_APPEND - 权限参数(如
0644)在 Windows 上被忽略,实际权限由系统策略决定
遍历目录别硬写递归,用 filepath.WalkDir(Go 1.16+)
filepath.Walk 已被标记为 deprecated,新代码应使用 filepath.WalkDir。它按字典序访问条目,且支持在回调中返回 filepath.SkipDir 跳过子树,比自己维护栈更可靠。
立即学习“go语言免费学习笔记(深入)”;
-
回调函数签名是
func(path string, d fs.DirEntry, err error) error,其中d可快速获取名称、是否为目录(d.IsDir())、大小(d.Info().Size()),避免重复调os.Stat - 路径拼接务必用
filepath.Join("dir", "file.txt"),而不是字符串拼接"dir/file.txt",否则在 Windows 下失效 - 若需过滤特定扩展名(如
.go),在回调里用strings.HasSuffix(d.Name(), ".go"),不要依赖d.Type()判断文件类型
检查文件是否存在或类型,避免竞态,用 os.Stat + os.IsNotExist
用 os.Stat 获取文件元信息是最通用方式,但注意:它不保证“存在即刻可读”,因为权限或文件状态可能在调用后瞬间变化;也不能替代业务逻辑中的打开/读取操作。
- 判断存在性:先
_, err := os.Stat(path),再if os.IsNotExist(err),不要用err == os.ErrNotExist,因底层错误可能是包装过的 - 区分文件/目录:
fi, _ := os.Stat(path); fi.IsDir()比os.IsDirectory(不存在)更直接;注意符号链接需用os.Lstat避免跟随 - 检查可执行权限:
fi.Mode()&0111 != 0(对应 user/group/other 的 x 位),但 Windows 不支持该位,结果恒为 false
真正难的是在并发场景下确保操作原子性——os 包本身不提供文件锁,os.Rename 虽在同磁盘上是原子的,但跨设备会退化为拷贝+删除;临时文件名要用 os.CreateTemp 生成,别手搓 fmt.Sprintf("tmp_%d", time.Now().Unix())。










