
本文详解如何使用 bufio.newreader 替代 fmt.scanln 正确读取含空格的用户输入,并将其完整保存为 .txt 文件,避免命令行解析错误与截断问题。
本文详解如何使用 bufio.newreader 替代 fmt.scanln 正确读取含空格的用户输入,并将其完整保存为 .txt 文件,避免命令行解析错误与截断问题。
在 Go 中实现文本文件保存时,一个常见却容易被忽视的问题是:如何可靠读取包含空格、制表符或换行符的用户输入? 原始代码中使用 fmt.Scanln 会导致输入被按空白字符(空格、制表符、换行)分割,仅捕获第一个单词——这正是出现 $ title 和 command not found 错误的根本原因:Shell 将未加引号的多词输入(如 Here is a title)误判为多个独立命令执行。
正确做法是使用 bufio.NewReader(os.Stdin) 配合 ReadString('\n'),它以换行符为界完整读取一行,保留所有中间空格和标点。配合 strings.TrimSpace 可安全去除首尾换行符与空格,确保文件名和内容语义准确。
以下是优化后的完整实现:
package main
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
)
// Document 表示文档结构,含标题与原始字节内容
type Document struct {
Title string
Body []byte
}
// Save 将文档内容写入以标题命名的 .txt 文件,权限设为 0600(仅所有者可读写)
func (p *Document) Save() error {
filename := p.Title + ".txt"
return ioutil.WriteFile(filename, p.Body, 0600)
}
// LoadPage 从磁盘加载指定标题的文档
func LoadPage(title string) (*Document, error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &Document{Title: title, Body: body}, nil
}
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Title: ")
title, err := reader.ReadString('\n')
if err != nil {
log.Fatal("failed to read title:", err)
}
title = strings.TrimSpace(title) // 清除 \n 和首尾空格
fmt.Print("Enter Body: ")
body, err := reader.ReadString('\n')
if err != nil {
log.Fatal("failed to read body:", err)
}
body = strings.TrimSpace(body)
// 构建并保存文档
doc := &Document{Title: title, Body: []byte(body)}
if err := doc.Save(); err != nil {
log.Fatal("failed to save file:", err)
}
// 加载并打印内容,验证保存成功
loaded, err := LoadPage(title)
if err != nil {
log.Fatal("failed to load saved file:", err)
}
fmt.Println("Saved content:")
fmt.Println(string(loaded.Body))
}✅ 关键改进说明:
- ✅ bufio.NewReader(os.Stdin) 提供面向行的输入流,ReadString('\n') 确保整行读取(含空格),无截断;
- ✅ strings.TrimSpace 移除 ReadString 附带的尾部 \n 及可能的首尾空格,防止生成 My Title.txt\n 这类非法文件名;
- ✅ 所有 I/O 错误均显式检查并 log.Fatal,避免静默失败;
- ✅ 方法名改为 Save/LoadPage(Go 习惯大驼峰导出函数),提升可读性与一致性;
- ✅ 权限 0600 合理限制文件访问,符合安全实践。
⚠️ 注意事项:
- 文件名中若含 /, *, ?, 等特殊字符,可能导致创建失败或路径遍历风险。生产环境建议对 title 进行规范化(如只保留字母、数字、下划线、短横线);
- ioutil 已在 Go 1.16+ 被 os.WriteFile / os.ReadFile 取代,新项目推荐升级使用(二者接口更简洁,且底层复用相同逻辑);
- 若需支持中文标题或特殊编码,请确保终端编码为 UTF-8(现代系统默认满足),Go 字符串原生支持 UTF-8。
掌握这一输入处理模式,不仅解决 TXT 保存问题,更是构建健壮 CLI 工具的基础能力。










