【问题标题】:Reading from stdin in golang从 golang 中的标准输入读取
【发布时间】:2015-03-15 13:07:20
【问题描述】:

我正在尝试从 Golang 中的 Stdin 读取数据,因为我正在尝试为 Erlang 实现驱动程序。我有以下代码:

package main

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

func main() {
    go func() { 
        stdout := bufio.NewWriter(os.Stdin) 
        p := []byte{121,100,125,'\n'}
        stdout.Write(p)
        }()
    stdin := bufio.NewReader(os.Stdin)
    values := make([]byte,4,4)
    for{
        fmt.Println("b")
        if read_exact(stdin) > 0 {
            stdin.Read(values)
            fmt.Println("a")
            give_func_write(values)
        }else{
            continue
        }
    }
}




func read_exact(r *bufio.Reader) int {
    bits := make([]byte,3,3)
    a,_ := r.Read(bits)
    if a > 0 {
        r.Reset(r)
        return 1
    }
    return -1
}

func give_func_write(a []byte) bool {
    fmt.Println("Yahu")
    return true
}

但是,似乎永远无法到达give_func_write。我试图在 2 秒后启动一个 goroutine 来写入标准输入来测试这个。

我在这里缺少什么? 还有r.Reset(r)这一行。这在go中有效吗?我试图实现的只是从文件开头重新开始读取。有没有更好的办法?

编辑

玩了之后发现代码卡在read_exact函数中的a,_ := r.Read(bits)

【问题讨论】:

  • @jimt 我想我需要有一个协议,在该协议中我发送一个\n 以使输入工作,同时在阅读时丢弃它。出于测试目的,换行符的二进制表示是什么? (表达这个问题的更好方法是:我需要在我的字节切片中包含什么数字才能有换行符)?
  • 0x0a 应该可以解决问题。
  • @jimt 检查我的新代码。 b 只打印一次。
  • p := []byte{121,100,125,125,111,100,161,152, 0x0a} 查看此示例:play.golang.org/p/QMOPsPWF7t 您可以在自己的系统上将stdin 字节缓冲区替换为os.Stdin。操场不允许使用os.Stdin

标签: go


【解决方案1】:

我想我需要一个协议,在其中我发送一个 \n 到 使输入工作,同时在阅读时丢弃它

不,你没有。 Stdin 仅在绑定到终端时才进行行缓冲。您可以运行您的程序prog < /dev/zerocat file | prog

bufio.NewWriter(os.Stdin).Write(p)

您可能不想写信给stdin。详情见“Writing to stdin and reading from stdout”。

嗯,我不太清楚你想要达到什么目的。我假设您只想通过固定大小的块从stdin 读取数据。为此使用io.ReadFull。或者,如果您想使用缓冲区,您可以使用Reader.PeekScanner 来确保特定数量的字节可用。我已经改变了你的程序来演示io.ReadFull的用法:

package main

import (
    "fmt"
    "io"
    "time"
)

func main() {
    input, output := io.Pipe()

    go func() {
        defer output.Close()
        for _, m := range []byte("123456") {
            output.Write([]byte{m})
            time.Sleep(time.Second)
        }
    }()

    message := make([]byte, 3)
    _, err := io.ReadFull(input, message)
    for err == nil {
        fmt.Println(string(message))
        _, err = io.ReadFull(input, message)
    }
    if err != io.EOF {
        panic(err)
    }
}

您可以轻松地将其拆分为两个程序并以这种方式进行测试。只需将input 更改为os.Stdin

【讨论】: