如何使用Golang按行读取大文件_Golangbufio Scanner文件行读取技巧汇总

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。正确姿势是流式打开 + 扫描。

  • 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、清好换行符、关好文件句柄,大文件就读得既稳又省。