英文:
How to read bytewise from stdin?
问题
in, out := bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)
for {
c, err := in.ReadByte()
if err == io.EOF {
break
}
out.WriteByte(c)
}
我想从标准输入流逐字节读取。与Read
方法不同,ReadByte
似乎不会返回io.EOF
。如果所有字节都已读取,我该如何跳出循环?
英文:
in, out := bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)
for {
c, err := in.ReadByte()
if err == io.EOF {
break
}
out.WriteByte(c)
}
I want to read bytewise from the stdin stream. Unlike the Read
methodReadByte
doesn't seem to return io.EOF
. How can I break if all bytes have been read?
答案1
得分: 2
这不是Reader.ReadByte()
实现的问题,也不是bufio.NewReader()
的问题。
看看这个例子来证明:
buf := bytes.NewBufferString("Hello World!\n")
in := bufio.NewReader(buf)
for {
c, err := in.ReadByte()
if err == io.EOF {
break
}
fmt.Print(string(c))
}
运行上述代码,会输出:
Hello World!
并且正常终止。
你的问题出在os.Stdin
上。从它读取是特定于其来源的。如果它是你的终端,从中读取会简单地阻塞而不报告io.EOF
。看看这个例子来证明:
in := bufio.NewReader(os.Stdin)
for {
fmt.Println("Reading.")
c, err := in.ReadByte()
if err == io.EOF {
break
}
fmt.Print(string(c))
}
它的输出是:
Reading.
然后什么都不会发生。没有新的迭代,它被阻塞了。现在,如果你输入一行并按下<kbd>Enter</kbd>,例如输入Go!
,输出将是:
Go!
GReading.
oReading.
!Reading.
Reading.
然后再次等待新的输入。正如你所看到的,数据是按行提供/可用的。这就是你的终端的工作方式:当你输入一行时,它不会发送到os.Stdin
。一旦你按下<kbd>Enter</kbd>,整行就被提供并可以从os.Stdin
中获取。这就是我们看到的:输入Go!
的每个字母和一个换行符。我们看到Reading.
文本在每次迭代中打印。在输入被消耗完之后,in.ReadByte()
再次被阻塞,等待新的输入。它不会报告io.EOF
。
现在试试以下操作:创建一个文件,例如a.txt
,并将其编辑为一行:Go!
和一个换行符。现在将此文件作为标准输入传递给你的程序:
go run play.go < a.txt
运行它,我们会看到:
Reading.
GReading.
oReading.
!Reading.
Reading.
Reading.
然后它终止了,所以它正常工作!它之所以正常工作,是因为这次os.Stdin
的来源不是你的控制台/终端,而是文件的内容,一旦它被消耗完,尝试从os.Stdin
读取将正确报告io.EOF
。
英文:
This is not an issue of the Reader.ReadByte()
implementation, nor that of bufio.NewReader()
.
See this example to prove it:
buf := bytes.NewBufferString("Hello World!\n")
in := bufio.NewReader(buf)
for {
c, err := in.ReadByte()
if err == io.EOF {
break
}
fmt.Print(string(c))
}
When running, the above prints
Hello World!
And terminates properly.
Your issue is with os.Stdin
. Reading from it is specific to its source. If it is your terminal, reading from it simply blocks and does not report io.EOF
. See this example to prove it:
in := bufio.NewReader(os.Stdin)
for {
fmt.Println("Reading.")
c, err := in.ReadByte()
if err == io.EOF {
break
}
fmt.Print(string(c))
}
Its output is:
Reading.
And nothing happens. There is no new iteration, it is blocked. Now if you enter a line and press <kbd>Enter</kbd>, e.g. you enter Go!
, output will be:
Go!
GReading.
oReading.
!Reading.
Reading.
And again, waits for new input. As you can see, data is fed / available per line. This is what your terminal does: while you enter your line, it is not sent to os.Stdin
. Once you press <kbd>Enter</kbd>, the whole line is fed and is available from os.Stdin
. This is what we see: each letter of the input Go!
and a newline character. And we see the Reading.
text printed for each iteration. After the input is consumed, in.ReadByte()
is blocked again, waiting for new input. It does not report io.EOF
.
Now try the following: create a file e.g. a.txt
and edit it to have one line: Go!
and a newline. Now feed this file as the standard input to your program:
go run play.go < a.txt
Running it we'll see:
Reading.
GReading.
oReading.
!Reading.
Reading.
Reading.
And it terminates so it works! It works because this time the source of os.Stdin
is not your console / terminal, but the contents of a file, and once it's consumed, attempting to read from os.Stdin
will properly report io.EOF
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论