
本文详解如何在 go 中安全、高效地逐行读取含整数的文本文件,并解决因换行符残留导致 `strconv.atoi` 解析失败的常见问题。
在 Go 中逐行读取整数文本文件时,一个典型陷阱是:使用 bufio.Reader.ReadString('\n') 会将换行符 \n(或 Windows 下的 \r\n)包含在返回字符串中。正如问题中所观察到的——lineStr 长度为 4 而非 2,且内容实际为 "10\n"(UTF-8 编码下 '\n' 占 1 字节,'1' 和 '0' 各占 1 字节,共 3 字节;若输出显示长度为 4,很可能文件为 CRLF 换行,即 "10\r\n"),这导致 strconv.Atoi("10\n") 或 strconv.ParseUint("10\n", 0, 64) 无法识别为有效整数,返回 0 和错误。
虽然可通过 strings.TrimSpace(line) 手动清理空白符(包括 \n, \r, \t, 空格等),但更推荐、更符合 Go 习惯的方式是使用 bufio.Scanner:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
file, err := os.Open("input.txt")
if err != nil {
panic(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text() // ✅ 自动去除行尾换行符,不包含 \n 或 \r\n
num, err := strconv.Atoi(line)
if err != nil {
fmt.Printf("警告:跳过无效行 '%s' — %v\n", line, err)
continue
}
fmt.Printf("解析成功:'%s' → %d\n", line, num)
}
if err := scanner.Err(); err != nil {
panic(fmt.Sprintf("读取文件时出错:%v", err))
}
}✅ 关键优势:
- scanner.Text() 返回的字符串已自动剥离行终止符(\n、\r\n),无需额外 Trim;
- 内部按行缓冲,内存友好,适合大文件;
- 错误处理清晰:scanner.Err() 可捕获 I/O 错误,strconv.Atoi 的错误则用于校验数据格式。
⚠️ 注意事项:
- bufio.Scanner 默认单行最大长度为 64KB(bufio.MaxScanTokenSize),若需读取超长行,请提前设置:
scanner := bufio.NewScanner(file) scanner.Buffer(make([]byte, 64*1024), 1<<20) // 最大支持 1MB 行
- 始终检查 strconv.Atoi 的错误返回,避免静默失败(如空行、字母混入等);
- 不要忽略 scanner.Err() —— 它是检测读取过程中底层 I/O 错误(如磁盘损坏、权限不足)的唯一途径。
总结:避免直接使用 ReadString('\n') 处理行数据;优先选用 bufio.Scanner,它专为“按行读取”设计,语义清晰、健壮性强、符合 Go 生态最佳实践。










