
本文详解 go 语言中使用 bufio.scanner 安全、高效地逐行读取文件的标准实践,涵盖基础用法、错误处理、内存注意事项及常见陷阱规避方法。
本文详解 go 语言中使用 bufio.scanner 安全、高效地逐行读取文件的标准实践,涵盖基础用法、错误处理、内存注意事项及常见陷阱规避方法。
在 Go 中实现“逐行读取文件”这一经典操作,并非依赖循环判断 EOF(Go 不提供显式 EOF 检测接口),而是通过 bufio.Scanner 的流式扫描机制完成——它自动按行分割、缓冲输入,并在每次调用 Scan() 时返回是否成功读取下一行。这是官方推荐、简洁且内存友好的方式。
以下是最小可行示例:
package main import ( "bufio" "fmt" "os" ) func main() { file, err := os.Open("path/to_file") if err != nil { panic(fmt.Sprintf("无法打开文件: %v", err)) } defer file.Close() // 关键:务必关闭文件句柄 scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() // 获取当前行(不含换行符) fmt.Println(line) } // 检查扫描过程中是否发生错误(如 I/O 错误) if err := scanner.Err(); err != nil { panic(fmt.Sprintf("读取文件时出错: %v", err)) } }
⚠️ 重要注意事项:
- 必须显式检查 scanner.Err():Scan() 返回 false 可能因到达文件末尾(正常)或发生错误(异常),仅靠循环退出无法区分;遗漏此检查将掩盖 I/O 故障。
- 避免忽略 os.Open 错误:示例中已补全错误处理与 defer file.Close(),生产代码严禁使用 _ 忽略错误或忘记关闭文件。
- 默认行长度限制为 64KB:若需读取超长行(如日志中的堆栈跟踪),应预先调用 scanner.Buffer(make([]byte, 64*1024), 1
- Text() 返回的字符串生命周期仅在下次 Scan() 前有效:若需长期保存某行内容,请显式 line := String(append([]byte(nil), scanner.Bytes()…)) 或直接复制字节切片。
总结:Go 的逐行读取不是“手动 while + EOF”,而是基于 bufio.Scanner 的声明式迭代。它兼顾性能、安全与可维护性——正确处理错误、及时释放资源、合理配置缓冲,即可稳健应对绝大多数文本处理场景。