用 io.Copy 流式写入配合 os.OpenFile 和 O_APPEND 是 Go 写超大文件最稳、最省内存的方式,因 os.WriteFile 会全量加载内存易 OOM,而 io.Copy 使用固定 32 KiB 缓冲区零拷贝循环读写。

用 io.Copy 流式写入,配合 os.OpenFile 和 O_APPEND 控制追加行为,是 Go 写超大文件最稳、最省内存的方式。
为什么不能用 os.WriteFile 写超大文件
它会把整个数据一次性加载进内存再调用系统 write,对几百 MB 以上的文件极易触发 OOM;即使你传的是 []byte 切片,底层仍会做完整拷贝。错误信息如 runtime: out of memory 或 fatal error: runtime: out of memory 就是典型信号。它只适合 ≤几 MB 的配置、快照类小数据。
io.Copy 是流式写入的黄金标准
它不分配额外切片,内部用固定 32 KiB 缓冲区循环读写,零拷贝开销,自动传播 EOF 和错误。适用于 io.ReadCloser(如 HTTP 响应体)、io.Reader(如压缩流、加密流)等任意流源:
- 直接对接网络响应:
io.Copy(outFile, res.Body),写完别忘res.Body.Close() - 写本地大文件时,
outFile应由os.OpenFile打开,并确保 flags 包含O_WRONLY和O_CREATE - 若需追加,必须显式加
O_APPEND;漏掉它会导致从头覆盖——前几 MB 看似正常,但实际已破坏原文件 - 路径含多级目录(如
"logs/2026/09/app.log")时,务必提前os.MkdirAll(filepath.Dir(path), 0755)
bufio.Writer 适合高频小块写入,但 Flush 容易被忽略
当你要逐条写日志、CSV 行或结构化记录时,bufio.Writer 能聚合小写请求,减少 syscall 次数。但它不是“设了就完事”:
立即学习“go语言免费学习笔记(深入)”;
- 缓冲区大小建议设为
64 * 1024(64 KiB):太小(如 4 KiB)起不到聚合效果;太大(如 1 MiB)会延迟落盘,断电即丢数据 - 必须显式调用
wr.Flush();defer wr.Flush()不可靠,因为Close()不保证 flush - 不要混用:
wr.WriteString("a")+file.Write([]byte("b"))会导致字节序错乱,因两者共享同一 fd 但缓冲逻辑不同 - 并发写同一文件必须加锁,
bufio.Writer本身不支持 goroutine 安全
超大文件写入后要不要 Sync
写完调用 outFile.Sync() 可强制刷盘,避免数据滞留在 OS 缓存中。但它会阻塞并增加延迟,是否启用取决于场景:
- 日志归档、备份文件等可靠性优先场景:建议加
Sync - 临时导出、可重试任务:可跳过,靠 OS 自行刷盘即可
- SSD 上延迟较低,HDD 上影响更明显;若已用
io.Copy,Sync是最后一步兜底,不是替代方案
真正容易被忽略的点是:O_APPEND 必须和 O_WRONLY、O_CREATE 同时出现;bufio 的 Flush 不是可选项而是必选项;Sync 不是性能优化手段而是数据可靠性补丁。这些细节在压测时可能不暴露,上线后却导致文件损坏或数据丢失。


















