Go写文件需据场景选方案:小文件用os.WriteFile(覆盖、简洁);高吞吐用bufio.Writer+os.File(可追加、需Flush);极端性能可 syscall.Write(零拷贝、不跨平台);关键数据须f.Sync保证落盘。

Go 语言写文件本身很简单,但实际项目中常因忽略缓冲、错误处理或同步策略,导致性能差、数据丢失或竞态问题。
用 os.WriteFile 快速写小文件(≤几 MB)
适合配置文件、日志快照、临时导出等一次性写入场景。它内部自动处理打开、写入、关闭,代码最简,但会覆盖原文件且无增量能力。
- 若文件已存在,
os.WriteFile总是覆盖,不支持追加 - 底层调用
os.OpenFile+Write+Close,对大文件反复拷贝内存,性能急剧下降 - 错误只返回一次(写失败时),无法区分是权限不足、磁盘满还是路径不存在
示例:
err := os.WriteFile("config.json", []byte(`{"mode":"prod"}`), 0644)
if err != nil {
log.Fatal(err) // 注意:这里 panic 可能掩盖真实原因
}
用 bufio.Writer + os.File 控制缓冲与追加
这是高吞吐写入(如日志、CSV 流、批量导出)的推荐方式。关键在显式管理文件句柄和缓冲区大小,避免频繁系统调用。
立即学习“go语言免费学习笔记(深入)”;
- 必须手动调用
wr.Flush(),否则内容可能滞留在内存缓冲中未落盘 -
bufio.NewWriterSize(f, 4096)中的缓冲尺寸建议设为 4KB 或 64KB;太小失去缓冲意义,太大增加延迟和内存占用 - 追加写需用
os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644),漏掉os.O_APPEND会从头覆盖 - 并发写同一文件必须加锁(
sync.Mutex),bufio.Writer本身不是 goroutine 安全的
示例(安全追加):
f, _ := os.OpenFile("log.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
defer f.Close()
wr := bufio.NewWriterSize(f, 64*1024)
wr.WriteString("req_id: abc123\n")
wr.Flush() // 忘记这行 = 数据可能没写进去
用 syscall.Write 或 unsafe 零拷贝写(仅限极端性能场景)
标准库的 Write 在小数据量时有额外切片头开销;当单次写入数万次、每次仅几个字节(如高频指标打点),可考虑绕过 bufio 和 os.File.Write 的封装。
- 直接调用
syscall.Write(int(f.Fd()), buf)省去 Go runtime 的切片检查和复制,但需确保buf生命周期覆盖系统调用完成 - 不能用于 Windows(
syscall.Write不可用),跨平台项目慎用 - 无法自动处理
EINTR重试,需自行循环判断返回值 - 绝大多数业务无需此优化——先压测确认
bufio.Writer是瓶颈,再动手
真正容易被忽略的是:写入后是否需要 fsync。比如金融类交易日志,Write 返回成功只表示进内核页缓存,断电仍可能丢失。此时必须跟 f.Sync(),但会显著拖慢吞吐。要不要做,得看你的数据一致性边界在哪里。











