在内存有限的设备上,需要读取大文本文件时,可以使用逐行读取方式来处理。
一、使用 bufio.Scanner
在 Go 语言中,逐行读取文本文件最高效、内存友好的方式是使用 bufio.Scanner。它适用于绝大多数场景(包括大文件),且代码简洁。
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
file, err := os.Open("data.txt")
if err != nil {
log.Fatal(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 {
log.Fatal(err)
}
}
说明
scanner.Scan():每次读取一行,返回true表示还有下一行。scanner.Text():返回当前行的字符串(自动去除\n或\r\n)。- 自动处理不同平台的换行符(
\n,\r\n)。 - 内存效率高:不会一次性加载整个文件到内存,适合 GB 级大文件。
注意事项
超长行限制,bufio.Scanner 默认最大行长度为 64KB。如果某行超过这个长度,会报错:
bufio.Scanner: token too long
解决方法:修改buf最大长度。
scanner := bufio.NewScanner(file)
const maxCapacity = 1024 * 1024 // 1MB
buf := make([]byte, maxCapacity)
scanner.Buffer(buf, maxCapacity)
for scanner.Scan() {
line := scanner.Text()
// ...
}
二、使用bufio.Reader(更底层,支持任意长度)
reader := bufio.NewReader(file)
for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
if len(line) > 0 {
// 处理最后一行(无换行符)
fmt.Print(line)
}
break
}
log.Fatal(err)
}
fmt.Print(line) // 注意:line 包含 '\n'
}
适用于需要精确控制或处理超长行的场景。
总结
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
bufio.Scanner |
简洁、高效、自动去换行 | 默认行长 ≤ 64KB | 绝大多数情况(推荐) |
bufio.Reader |
支持任意行长 | 代码稍复杂,需手动处理 EOF 和换行符 | 超长行、特殊格式 |
评论区