Go写文件需用os.OpenFile精确控制模式与权限,必查Write和Close的错误,大文件用bufio.Writer批量写并显式Flush,os.WriteFile仅适用于小数据覆盖写。

Go 写文件不难,但直接用 os.Create 或 ioutil.WriteFile(已弃用)容易丢数据、出错不报、权限失控——关键在选对函数、处理错误、控制缓冲和同步。
用 os.OpenFile 控制写入模式和权限
多数人一上来就用 os.Create,但它等价于 os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666),无法指定只写、追加、或自定义权限。实际中更常用 os.OpenFile 显式控制:
-
os.O_WRONLY | os.O_CREATE | os.O_TRUNC:覆盖写(默认行为) -
os.O_WRONLY | os.O_CREATE | os.O_APPEND:追加写,避免覆盖已有内容 - 第三个参数是
perm,比如0644,不是 umask;若父目录不可写,即使这里设对也创建失败 - Windows 下注意路径分隔符,
filepath.Join比硬写"\"更安全
别跳过 file.Close() 和 err 检查
写完不 Close() 可能导致缓冲未刷盘、句柄泄漏、后续 os.Remove 失败(尤其 Windows)。而忽略 Write() 或 Close() 的返回 err,等于默认“一定成功”——但磁盘满、只读文件系统、NFS 超时都会在这里报错:
file, err := os.OpenFile("log.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err) // 不要只 print
}
defer file.Close() // defer 在函数 return 前执行,但需确保它真被调用
_, err = file.Write([]byte("hello
"))
if err != nil {
log.Fatal(err) // Write 失败 ≠ Close 失败,必须分开检查
}
err = file.Close() // Close 可能因 flush 失败而报 err,不能省
if err != nil {
log.Fatal(err)
}
大文件或高频率写入要用 bufio.Writer
每次 Write() 都触发一次系统调用,小数据频繁写(如逐行日志)性能极差。用 bufio.NewWriter 包一层,批量刷盘:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 默认缓冲区 4KB,可传
bufio.NewWriterSize(file, 64*1024)调整 - 记得调
wr.Flush()——Close()不自动 flushbufio.Writer,只关底层 file - 如果程序可能 panic,用
defer wr.Flush()不保险(panic 时 defer 会执行,但若没 recover 仍可能丢最后一批数据),关键场景建议显式Flush()后再Close()
os.WriteFile 适合简单覆盖写,但别用于大文件
os.WriteFile 是最简接口:os.WriteFile("a.txt", []byte("data"), 0644)。它内部做了 OpenFile → Write → Close 全流程,方便但有代价:
- 必须把全部内容加载进内存,写 500MB 文件?先分配 500MB slice
- 没有追加选项,只能覆盖
- 权限参数是
os.FileMode,不是字符串,0644要写对,"0644"会编译失败
真正容易被忽略的是:哪怕只写几 KB,如果目标路径所在磁盘只剩 1KB 空间,os.WriteFile 也会在 Write 阶段失败,而不是创建文件时——错误时机比预想的晚。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










