在 golang 中从 stdin 读取输入

Reading input from stdin in golang

我有这个代码:

func readTwoLines() {
    reader := bufio.NewReader(os.Stdin)
    line, _ := reader.ReadString('\n')
    fmt.Println(line)
    line, _ = reader.ReadString('\n')
    fmt.Println(line)
}

对于输入:

hello
bye

输出是:

hello
bye

一切正常。但是现在,如果我每行创建一个 reader:

func readTwoLines() {
  line, _ := bufio.NewReader(os.Stdin).ReadString('\n')
  fmt.Println(line)
  line, err := bufio.NewReader(os.Stdin).ReadString('\n')
  if err != nil {
    fmt.Println(err)
  }    
  fmt.Println(line)
}

阅读第二行时出现EOF错误。

为什么会这样?

对于简单的使用,Scanner可能更方便。
你不应该使用两个阅读器,第一次读取,缓冲 4096 字节的输入:

// NewReader returns a new Reader whose buffer has the default size.
func NewReader(rd io.Reader) *Reader {
  return NewReaderSize(rd, defaultBufSize)
}

defaultBufSize = 4096

甚至您的输入包含 4000 个字节,第二次读取仍然没有任何可读取的内容。 但如果您输入超过 4096 字节的输入,它将起作用。


If ReadString encounters an error before finding a delimiter, it returns the data read before the error and the error itself (often io.EOF).

这是设计使然,请参阅文档:

// ReadString reads until the first occurrence of delim in the input,
// returning a string containing the data up to and including the delimiter.
// If ReadString encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end in
// delim.
// For simple uses, a Scanner may be more convenient.
func (b *Reader) ReadString(delim byte) (string, error) {
    bytes, err := b.ReadBytes(delim)
    return string(bytes), err
}

试试这个:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
        fmt.Println(scanner.Text()) // Println will add back the final '\n'
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, "reading standard input:", err)
    }
}

运行:

go run m.go < in.txt

输出:

hello
bye

in.txt 文件:

hello
bye

希望对您有所帮助。