bufio.scanner默认缓冲区仅64kb,超长行触发bufio.errtoolong导致scan()返回false且静默失败;必须显式调用scanner.buffer()扩容并检查scanner.err()。

bufio.Scanner 默认缓冲区太小,读大行或含空格的输入时容易 silently 失败——必须显式调大 ScanLines 或重设缓冲区。
为什么 Scanner 会突然不读输入?
默认情况下,bufio.Scanner 的缓冲区只有 64KB,且对单行长度有硬限制(MaxScanTokenSize,默认 65536)。一旦某行超长,scanner.Scan() 返回 false,而 scanner.Err() 会是 bufio.ErrTooLong——但很多人没检查这个错误,导致程序“卡住”或“跳过输入”。
- 常见现象:
fmt.Println(scanner.Text())突然 panic 或输出为空,scanner.Scan()返回 false 却没报错 - 典型场景:读取用户粘贴的 JSON 片段、Base64 字符串、日志行、带空格的路径名
- 关键点:这不是 EOF,而是缓冲区溢出;
scanner.Err()必须在Scan()返回 false 后立即检查
如何安全地读取任意长度的单行输入?
最直接的方式是用 bufio.NewReader(os.Stdin) 配合 ReadString('\n'),但若坚持用 Scanner,就得重设缓冲区。注意:不能只改 Buffer,还要确保 Split 函数能处理长 token。
一款AI演示文稿工具,主要用于DeepSeek AI加持,输入主题生成专业PPT,支持Word/PDF等45种文档导入,职场汇报、教学提案轻松搞定,适合需要提升相关任务效率的用户。
- 调用
scanner.Buffer(make([]byte, 0, 1024*1024), 1024*1024)—— 第二个参数是最大 token size,必须 ≥ 缓冲底层数组 cap - 如果读的是整块输入(非按行),可改用
scanner.Split(bufio.ScanBytes)或自定义 split 函数 - 别设无限大:1MB 是较稳妥的上限;超过需考虑流式解析,而非全加载
scanner := bufio.NewScanner(os.Stdin) scanner.Buffer(make([]byte, 0, 1 <h3>Scanner 和 ReadString 性能差异在哪?</h3> <p><code>Scanner</code> 是带词法切分的封装,适合按行、按空格、按字节等规则扫描;<code>ReadString</code> 是底层 I/O 原语,无切分开销。实际测下来,纯读行场景下两者吞吐接近,但 <code>Scanner</code> 多一层 copy 和边界判断。</p>
- 高吞吐批量读(如日志管道):优先用
ReadString或ReadLine,避免Text()的 string 转换开销 - 需要跳过空白、识别注释、按字段拆分:用
Scanner+ 自定义Split更清晰 - 注意:无论哪种方式,
os.Stdin默认是行缓冲(终端下),重定向文件或 pipe 时行为不变,但不会自动 flush
遇到含 \r\n 或混合换行符怎么办?
Scanner 默认用 ScanLines,它把 \r\n、\n、\r 都当作行结束,并自动去掉结尾的换行符。但如果你手动用 ReadString('\n'),就可能残留 \r(尤其 Windows 输入或 HTTP body)。
- 标准输入通常由 shell 处理换行,多数情况无需额外 trim;但若接收外部数据流,建议用
strings.TrimRight(line, "\r\n") - 不要依赖
scanner.Split(bufio.ScanLines)的“智能”——它不保证跨平台一致性,比如某些嵌入式终端可能发裸\r - 真正要健壮:自己写 split 函数,用
bytes.IndexAny(data, "\r\n")定位,再手动切分
缓冲区大小和错误检查不是可选项,是 Scanner 的使用契约。漏掉 scanner.Err() 检查,等于放弃对输入完整性的控制。










