bufio.Scanner 按行读取大文件最常用且稳妥,但默认64KB行长限制易触发ErrTooLong,需调用scanner.Buffer()自定义缓冲区大小。

用 bufio.Scanner 按行读取大文件是 Go 中最常用也最稳妥的方式,它内存友好、语法简洁、默认支持 UTF-8,但需注意几处关键细节才能真正“稳读大文件”。
默认 Scanner 有 64KB 行长度限制
Scanner 默认每行最多读 64KB,超长会报 bufio.ErrTooLong。处理日志、JSON 行、或含超长字段的 CSV 时很容易触发。
- 用
scanner.Buffer(make([]byte, 64*1024), 1 手动扩容缓冲区(例如设上限为 1MB) - 更健壮的做法:捕获错误并跳过异常行,避免整个流程中断
- 若确定行不会超长,可只调大第一个参数(初始缓冲),第二个参数(最大容量)保持合理即可
按行读取 ≠ 按 \n 切分 —— 注意换行符兼容性
Scanner 默认以 \n 为分隔符,对 Windows 的 \r\n 或旧 Mac 的 \r 不自动处理。实际读到的行末可能残留 \r,尤其在跨平台处理日志或配置文件时。
- 简单清洗:读完后用
strings.TrimRight(line, "\r\n") - 如需严格按 CRLF 分割,可自定义 SplitFunc,但多数场景 Trim 更轻量可靠
- 注意:UTF-8 BOM(
\uFEFF)也可能出现在首行开头,必要时一并 Trim
大文件别忘关文件,且优先用 os.Open 而非 ioutil.ReadFile
ioutil.ReadFile(或 os.ReadFile)会把整个文件加载进内存,GB 级文件直接 OOM。正确姿势是流式打开 + 扫描。
立即学习“go语言免费学习笔记(深入)”;
- 用
f, err := os.Open("big.log"),defer f.Close() - 传给 Scanner:
scanner := bufio.NewScanner(f) - 循环中用
for scanner.Scan() { line := scanner.Text() },不是scanner.Bytes()(后者不自动解码 UTF-8) - 退出前务必检查
scanner.Err(),判断是 EOF 还是真实 I/O 错误
需要更高性能?考虑 bufio.Reader + ReadString('\n')
Scanner 内部就是封装了 Reader,但多了词法分析逻辑。如果只要纯按行切分、不做 token 化,且对性能敏感(如每秒百万行解析),可手动用 Reader:
reader := bufio.NewReader(f)for { line, err := reader.ReadString('\n'); if err == io.EOF { break } else if err != nil { /* handle */ } }- 注意:
ReadString返回的 line 包含结尾的\n,需用strings.TrimSuffix(line, "\n") - 比 Scanner 略快、更可控,但少了缓冲区自动扩容和错误分类,需自行兜底
基本上就这些。Scanner 足够好用,关键在理解它的边界 —— 不是黑盒,而是带默认配置的流处理器。调对 Buffer、清好换行符、关好文件句柄,大文件就读得既稳又省。










