io.Copy 比 os.ReadFile 更适合大文件,因其用固定32KB缓冲区流式处理,内存恒定;而 os.ReadFile 会一次性加载全文件到内存,易导致 OOM。
为什么 io.Copy 比 os.ReadFile 更适合大文件
因为 os.ReadFile 会一次性把整个文件加载进内存,1GB 文件就占 1GB 内存;而 io.Copy 默认用 32KB 缓冲区边读边写,内存占用恒定。实际项目中遇到 500MB 日志归档或视频转存时,直接 panic:out of memory 就是这么来的。
实操建议:
- 始终优先用
io.Copy处理 >10MB 的文件 - 若需自定义缓冲区大小(比如 SSD 上调高吞吐),传入带
io.CopyBuffer的版本 - 注意:源
io.Reader和目标io.Writer都必须支持流式操作,不能是已关闭的*os.File
如何安全地边读边处理(如 JSON 行解析)
常见错误是用 bufio.Scanner 读取超长行导致内存暴涨,或未检查 Err() 导致静默截断。正确做法是控制单次读取上限,并显式判断错误类型。
实操建议:
- 用
scanner := bufio.NewScanner(file)后立刻调scanner.Buffer(make([]byte, 4096), 1 限制最大行长度 - 每次
scanner.Scan()后必须检查scanner.Err(),尤其要区分io.EOF和bufio.ErrTooLong - 若处理的是结构化流(如 NDJSON),改用
json.Decoder的Decode()方法,它天然支持流式反序列化
os.OpenFile 的 flag 组合怎么选才不丢数据
误用 os.O_CREATE | os.O_WRONLY 而不加 os.O_TRUNC 会导致写入位置从文件开头开始覆盖,但旧数据尾部残留;加了 os.O_APPEND 又可能破坏原子性。日志轮转、断点续传这类场景极易出错。