Go语言中如何正确终止处于挂起状态的bufio.Scanner?
问题解答
bufio.Scanner的Scan()方法只有两种情况会返回false终止循环:
- 输入流读到
EOF(文件结束标记) - 读取过程发生底层IO错误
你遇到的挂起本质是输入流一直没有收到EOF,也没有发生错误,所以Scan()会一直阻塞等待新数据输入。
常见场景的终止方案
1. 终端STDIN输入场景(最常用)
直接通过系统快捷键发送EOF即可终止:
- Linux / macOS 按
Ctrl + D - Windows 按
Ctrl + Z后回车
2. 普通文件读取场景
你提到的「读取空文件挂起」属于误解:普通本地磁盘的0字节空文件,打开后首次调用Scan()就会检测到EOF直接返回false,不会阻塞。如果出现挂起,你读取的一定是管道、Socket、终端这类流式动态输入资源,而非静态磁盘文件。
3. 程序主动异步终止
如果需要代码层面主动控制终止时机(比如超时、收到中断信号时退出),只需主动关闭输入流即可,Scan()会立刻触发IO错误返回false,不需要做轮询检查。
示例代码如下:
package main import ( "bufio" "context" "fmt" "os" "os/signal" "syscall" "time" ) func main() { // 示例:设置5秒读取超时 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // 监听系统中断信号 sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) scanner := bufio.NewScanner(os.Stdin) done := make(chan error, 1) // 异步执行扫描逻辑 go func() { for scanner.Scan() { fmt.Println("收到输入:", scanner.Text()) } done <- scanner.Err() }() // 等待终止触发条件 select { case err := <-done: if err != nil { fmt.Fprintln(os.Stderr, "读取输入错误:", err) } fmt.Println("输入流读取完成,正常退出") case <-ctx.Done(): fmt.Println("读取超时,主动终止") _ = os.Stdin.Close() // 关闭输入流触发scanner退出 case <-sigCh: fmt.Println("收到中断信号,主动终止") _ = os.Stdin.Close() } }
内容的提问来源于stack exchange,提问作者Ien Nemski
相关产品推荐
相关产品推荐

