如何从stdin中按字节读取?

时间:2017-08-23 08:29:29

标签: go byte buffer stdin

in, out := bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)
for {
    c, err := in.ReadByte()
    if err == io.EOF {
        break
    }
    out.WriteByte(c)
}

我想从stdin流中逐字节读取。与Read方法ReadByte不同,它似乎不会返回io.EOF。如果已读取所有字节,我该怎么办?

1 个答案:

答案 0 :(得分:3)

这不是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.

没有任何反应。没有新的迭代,它被阻止。现在,如果您输入一行并按 Enter ,例如输入Go!,输出将为:

Go!
GReading.
oReading.
!Reading.

Reading.

再次等待新的输入。如您所见,每行都有数据输入/可用。这是您的终端所做的:当您输入行时,它不会发送到os.Stdin。按 Enter 后,整行将被输入并可从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