bufio.Scanner 不适合读大文件,因其默认64KB缓冲区遇超长行会panic;应改用bufio.Reader配合自定义缓冲、分块读取、Seek优化及并发限流等策略。
用 bufio.Scanner 读大文件会崩溃?别用它
bufio.Scanner 默认缓冲区只有 64KB,遇到超长行(比如单行几百 MB 的日志或 JSON)直接 panic:scanner: token too long。它本质是为“行清晰、长度可控”的场景设计的,不是为大文件流式处理准备的。
实操建议:
- 明确放弃
bufio.Scanner处理未知格式或可能含超长行的大文件 - 改用
bufio.Reader+ReadBytes('\n')或ReadString('\n'),自己控制缓冲区大小和错误恢复 - 若必须按行处理且行长不可控,先用
reader.Peek(n)预判长度,再决定是否分配内存
内存暴涨?用 io.ReadFull + 固定 buffer 分块读取
一次性 os.ReadFile 或 bytes.Buffer 加载 GB 级文件,Go 进程 RSS 瞬间飙高,还可能触发 GC 频繁停顿。关键不是“读得慢”,而是“不该把整块文件塞进堆里”。
实操建议:
- 用
os.Open获取*os.File,再套一层bufio.NewReaderSize(f, 1024*1024)(如 1MB 缓冲) - 循环调用
reader.Read(buf),buf是复用的[]byte(例如make([]byte, 64*1024)) - 避免在循环内做字符串转换(
string(b))——这会逃逸并复制内存;如需解析,直接操作[]byte
需要随机跳转读取?file.Seek() 比反复打开更高效
有些场景(如解析带偏移索引的日志、分片校验)需要从文件任意位置开始读。频繁 os.Open + os.Stat + 定位,开销远高于单次打开后多次 Seek。