bufio.scanner 默认缓冲区仅64kb,超长行会触发errtoolong panic;可通过scanner.buffer()自定义缓冲区大小来解决。

bufio.Scanner 默认缓冲区太小,超长行直接 panic
默认 64KB 单行限制在日志或导出数据里很常见——比如一条 JSON 行含 Base64 图片,轻松突破上限,scanner.Scan() 直接返回 scanner.ErrTooLong。这不是 bug,是设计防护。
- 调
scanner.Buffer(make([]byte, 64*1024), 1 把最大容量设为 1MB(第二个参数是上限) - 别只扩容量不设底层数组大小;第一个参数必须 ≥ 你预期的最小单行长度,否则仍会 panic
- 如果行长完全不可控(如混入二进制 blob),放弃
Scanner,改用bufio.NewReader+ReadBytes('\n')或手动扫描
逐行读取时内存被意外 hold 住
scanner.Bytes() 返回的是底层缓冲区切片,不是拷贝。只要这个字节切片被存进 map、slice 或闭包,整块缓冲区(比如 1MB)就无法被 GC 回收,内存只增不减。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 需要保存某行内容时,用
append([]byte(nil), line...)显式拷贝,或直接用scanner.Text()(它内部已拷贝) - 避免
strings.Split(string(b), "\n")——string(b)不分配新内存,但后续 split 出的字符串仍共享原底层数组 - 处理完一批行后,手动清空局部缓冲:
buf = buf[:0],帮助编译器识别可复用空间
并发读同一文件反而变慢
对单个大文本文件起多个 goroutine 分段 Seek + Read,在 HDD 或普通 SSD 上基本都会更慢。磁盘寻道开销远大于 CPU 解析时间,还可能触发内核锁竞争。
- 真正适合并发的场景:多个独立文件(如日志按天分片)、或文件已预分块存储(如对象存储的 multipart 上传结果)
- 若解析逻辑本身耗 CPU(如解密、正则匹配),可分离读取协程和 worker 协程,用 channel 中转,但 channel 缓冲区别设太大(
make(chan []byte, 16)足够) - 单文件流式处理,老老实实用一个
Scanner或Reader,省心且更快
os.Open 打开模式影响预读策略
默认 os.Open 等价于 os.OpenFile(name, os.O_RDONLY, 0),但内核对只读顺序访问有优化。加点系统级提示能进一步提速。
- Linux 下可用
syscall.O_DIRECT(需页对齐、绕过内核页缓存),适合超大文件顺序读,但错误处理更复杂 - 明确传
os.O_RDONLY而非默认值,让内核启用更激进的 read-ahead 策略 - Windows 不支持
O_DIRECT,跨平台项目慎用;mmap 在 Windows 支持弱,只读随机访问场景优先考虑bufio.NewReader+ 合理缓冲
Buffer 就万事大吉,也不是开了 goroutine 就自动变快。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










