英文:
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 (
"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)
}
}
run:
go run m.go < in.txt
output:
hello
bye
in.txt
file:
hello
bye
I hope this helps.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论