Reading input from stdin in golang

huangapple go评论77阅读模式
英文:

Reading input from stdin in golang

问题

我有这段 Go 代码:

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

一切正常。但是,如果我为每一行创建一个读取器:

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 错误。

为什么会发生这种情况?

英文:

I have this go code:

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

For the input:

hello
bye

the output is:

hello
bye

Everything ok. But now, if I create one reader per line:

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)
}

there is an EOF error, in the second line reading.

Why is it happening?

答案1

得分: 21

对于简单的用途,使用Scanner可能更方便。你不应该使用两个读取器,首先读取,缓冲区大小为4096字节:

// NewReader返回一个新的Reader,其缓冲区具有默认大小。
func NewReader(rd io.Reader) *Reader {
	return NewReaderSize(rd, defaultBufSize)
}

其中defaultBufSize = 4096

即使你的输入包含4000字节,第二次读取仍然没有内容可读。但是,如果你输入的内容超过4096字节,它将起作用。

如果在找到分隔符之前,ReadString遇到错误,它将返回错误之前读取的数据和错误本身(通常是io.EOF)。

这是设计如此,参见文档:

// ReadString读取输入中第一个分隔符之前的内容,返回包含数据和分隔符的字符串。
// 如果在找到分隔符之前,ReadString遇到错误,它将返回错误之前读取的数据和错误本身(通常是io.EOF)。
// 当且仅当返回的数据不以分隔符结尾时,ReadString返回err != nil。
// 对于简单的用途,使用Scanner可能更方便。
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会添加最后的'\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

希望这可以帮到你。

英文:

For simple uses, a Scanner may be more convenient.
You should not use two readers, first read, buffers 4096 bytes of input:

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

and defaultBufSize = 4096

and even your input contains 4000 bytes, still second read got nothing to read.
but if you enter input more than 4096 bytes it will work.


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

it is by design, see doc:

// 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
}

try this:

package main

import (
	&quot;bufio&quot;
	&quot;fmt&quot;
	&quot;os&quot;
)

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

run:

go run m.go &lt; in.txt

output:

hello
bye

in.txt file:

hello
bye

I hope this helps.

huangapple
  • 本文由 发表于 2017年8月28日 15:39:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/45914003.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定