
本文介绍 go 语言中逐行读取含整数的文本文件时,因换行符残留导致 `strconv` 解析失败的问题,并提供使用 `bufio.scanner` 的标准、健壮解决方案。
在 Go 中读取纯数字文本文件(每行一个整数)时,若直接使用 bufio.Reader.ReadString('\n'),会遇到一个常见陷阱:ReadString 返回的字符串包含换行符 \n(或 \r\n)本身。例如读取内容 "10\n",得到的 line 是长度为 3 的字节序列('1','0','\n'),转为 string 后并非 "10",而是 "10\n" —— 这正是 strconv.Atoi("10\n") 返回 0(错误)而非 10 的根本原因。len([]byte(line)) 显示为 4 可能是因文件含 UTF-8 BOM 或 Windows 换行符 \r\n,但核心问题始终是尾部控制字符未被清除。
推荐使用 bufio.Scanner,它专为按行扫描设计,默认以 \n 为分隔符,且自动去除行尾换行符,语义清晰、安全高效:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
file, err := os.Open("numbers.txt")
if err != nil {
panic(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lineStr := scanner.Text() // ✅ 自动去除 \n,返回纯净字符串
if num, err := strconv.Atoi(lineStr); err == nil {
fmt.Printf("Parsed: %s → %d\n", lineStr, num)
} else {
fmt.Printf("Invalid integer on line: %q, error: %v\n", lineStr, err)
}
}
if err := scanner.Err(); err != nil {
panic(err)
}
}⚠️ 注意事项:永远检查 scanner.Err():循环结束后需显式检查扫描过程是否发生 I/O 错误(如磁盘故障),否则可能静默丢失数据。避免忽略错误:示例中 strconv.Atoi 的错误未被丢弃,实际项目应根据业务逻辑处理(如跳过非法行、记录日志或中断流程)。替代方案说明:若必须用 ReadString,需手动裁剪:strings.TrimSpace(line) 或 line[:len(line)-1](仅当确定结尾为 \n 时),但易出错且不跨平台;Scanner 是 Go 官方推荐的标准做法。性能考量:Scanner 内部使用缓冲,对大文件友好;默认单行上限 64KB,如需处理超长行,可通过 scanner.Buffer(make([]byte, 64*1024), 1
总之,解析行数据时优先选择 bufio.Scanner,它消除了手动处理换行符的复杂性,让代码更简洁、健壮、符合 Go 的惯用风格。










