
本文详解如何在Go中正确读取标准输入的多行文本,并按空格分割每行字段;重点纠正fmt.Scanln仅读取首单词的误区,推荐使用bufio.Scanner替代,兼顾安全性、可扩展性与多行支持。
本文详解如何在go中正确读取标准输入的多行文本,并按空格分割每行字段;重点纠正`fmt.scanln`仅读取首单词的误区,推荐使用`bufio.scanner`替代,兼顾安全性、可扩展性与多行支持。
在Go语言中,fmt.Scanln(以及Scanf、Scan等)并非按“行”而是按“空白分隔的token”进行读取——它遇到第一个空格即停止,因此echo "A 1 2 3 4" | go run test.go中,Scanln(&line)只捕获到首字段 "A",后续数字被遗留在输入缓冲区,导致line内容不完整。这正是原始代码输出 entire: A 的根本原因。
要真正按整行读取输入,应使用 bufio.Scanner,它是Go标准库专为逐行扫描设计的高效、安全且默认限制行长度(防止内存溢出)的工具。以下为推荐实现:
package main
import (
"fmt"
"os"
"bufio"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text() // 完整获取一行(不含换行符)
fmt.Printf("Got line: %q\n", line)
fields := strings.Fields(line) // 按任意空白字符(空格、制表符等)分割,自动跳过前后及中间多余空白
for i, field := range fields {
fmt.Printf("field[%d]: %q\n", i, field)
}
}
// 检查扫描过程中是否发生错误(如I/O异常)
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "scan error: %v\n", err)
os.Exit(1)
}
}
✅ 优势说明:
-
scanner.Scan()返回true直至遇到EOF或错误,天然支持多行输入; -
scanner.Text()返回完整行内容,无截断风险; -
strings.Fields()是语义化分割——它将连续空白视为单一分隔符,并忽略首尾空白,比手动strings.Split(line, " ")更健壮; -
scanner.Err()可显式捕获底层I/O错误,提升程序鲁棒性。
⚠️ 注意事项:
- 默认单行最大长度为64KB(
bufio.MaxScanTokenSize),若需处理超长行,可通过scanner.Buffer(make([]byte, 64*1024), 1 手动扩容; - 不要混用
fmt.Scan*与bufio.Scanner读取同一os.Stdin,因缓冲机制冲突可能导致数据丢失; - 若需解析结构化数据(如带引号字段、转义字符),应考虑
encoding/csv或专用解析器,而非strings.Fields。
掌握 bufio.Scanner + strings.Fields 组合,是Go命令行工具开发中处理标准输入的基石实践。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











