必须流式处理大文件,禁用os.ReadFile/io.ReadAll;bufio.Scanner需显式调用scanner.Buffer设置初始缓冲和最大长度(如10MB)防panic,超长行场景改用scanner.Bytes()或手动file.Read,写慢设备须用1MB缓冲并显式Flush。

别用 os.ReadFile 或 io.ReadAll,它们会把整个文件 malloc 进堆,2GB 文件就申请 2GB 内存,GC 来不及回收,系统直接 kill。流式处理不是“可选优化”,而是唯一能跑通的路径。
bufio.Scanner 分行读文本时怎么防 panic
默认单行上限是 64KB,遇到含 base64、traceID 或长日志字段的行,scanner.Scan() 会 panic 报 scanner: token too long——这不是错误,是安全熔断。
- 必须显式调
scanner.Buffer(make([]byte, 64*1024), 10*1024*1024):第一个参数是初始缓冲,第二个是最大允许长度(如 10MB) - 若业务能容忍截断,改用
scanner.Bytes()获取原始字节切片,避免string转换开销 - 最后一行没换行符?
scanner.Scan()在 EOF 时仍返回该行,无需额外判断 —— 前提是没触发缓冲溢出
手动 file.Read 处理二进制或自定义格式文件
bufio.Scanner 不适用 protobuf 流、加密块、固定帧结构等非文本格式,必须自己控节奏。
- 预分配固定大小
[]byte(如make([]byte, 4*1024*1024)),在 for 循环中反复重用,避免 GC 压力 - 用
n, err := file.Read(buf)读取实际字节数;n == 0表示 EOF;注意err == io.ErrUnexpectedEOF是合法结束信号,不是错误 - 处理时只操作
buf[:n],别碰buf[n:],下次读会自然覆盖
io.CopyBuffer 写慢盘/网络文件时吞吐暴跌怎么办
默认 32KB 缓冲在 NFS、Ceph、USB 盘或高延迟云盘上会让吞吐暴跌,甚至卡死报 broken pipe。
立即学习“go语言免费学习笔记(深入)”;
- 根本原因是小 write 导致 syscall 过多 + 等待叠加,不是函数不行
- 用
io.CopyBuffer(dst, src, make([]byte, 1024*1024))把缓冲设成 1MB,NFS 上实测提速 3–5 倍 - 写目标文件时,务必先
Flush()再Close(),否则最后一块数据可能滞留在缓冲区丢失
所有流式操作都依赖资源及时释放:*os.File 必须 defer Close(),但写入后要先 Flush() 再 Close() —— 这不是理论风险,是线上丢数据的常见原因。


















