17370845950

如何在 Go 中逐行读取文本文件并正确解析整数字符串

本文介绍 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 的惯用风格。