bufio.Scanner默认单行上限64KB,超长即panic;需调用scanner.Buffer()设合理上限(如1MB),避免math.MaxInt32致OOM,长期保存行内容须深拷贝。

别用 os.ReadFile,它会把整个文件 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 时仍返回该行,无需额外判断 —— 前提是没触发缓冲溢出 - 别在循环里做阻塞操作(如同步 DB 写入、无 timeout 的 HTTP 请求),否则整条流水线卡死
json.Decoder 解析 JSON 数组时为什么总报 invalid character '}' after top-level value
这不是 JSON 语法错,是 decoder.Decode() 已退出数组上下文后还在继续调用,典型表现是多 Decode 了一次。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 正确流程:先
dec.Token()检查并跳过'[',再进for dec.More() { ... }循环 -
dec.More()返回false后必须break,否则下一次dec.Decode()会从]后开始读,自然报错 - 目标结构体用
json.RawMessage可跳过反序列化开销,适合只提取部分字段的场景 - 别用
decoder.Decode(&[]T{})—— 它仍会一次性分配整个切片底层数组,OOM 风险和json.Unmarshal一样高
手动 Read 分块处理二进制或自定义格式文件
当文件不是文本(比如 protobuf 流、加密块、固定帧结构),bufio.Scanner 不适用,得自己控节奏。
立即学习“go语言免费学习笔记(深入)”;
- 预分配固定大小
[]byte(如make([]byte, 1024*1024)),在for循环中反复重用,避免 GC 压力 - 用
n, err := file.Read(buf)读取实际字节数,n == 0表示 EOF;注意err == io.ErrUnexpectedEOF是合法结束信号,不是错误 - 处理时只操作
buf[:n],别碰buf[n:],下次读会自然覆盖 - 写目标文件时,用
io.CopyBuffer(dst, src, make([]byte, 1024*1024))替代默认io.Copy,NFS 或云盘上吞吐能提 3–5 倍
最易被忽略的点:所有流式操作都依赖资源及时释放。打开的 *os.File 必须 defer Close(),但写入后要先 Flush() 再 Close(),否则最后一块数据可能滞留在缓冲区丢失。这不是理论风险,是线上丢数据的常见原因。

















