英文:
Reading from stdin in golang
问题
我正在尝试从标准输入中读取数据,因为我正在为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)
这一行卡住了。
英文:
I'm trying to read from Stdin in Golang as I'm trying to implement a driver for Erlang. I have the following code:
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
}
However it seems that the give_func_write
is never reached. I tried to start a goroutine to write to standard input after 2 seconds to test this.
What am I missing here?
Also the line r.Reset(r)
. Is this valid in go? What I tried to achieve is simply restart the reading from the beginning of the file. Is there a better way?
EDIT
After having played around I was able to find that the code is stuck at a,_ := r.Read(bits)
in the read_exact
function
答案1
得分: 9
我猜我需要一个协议,在其中发送一个换行符\n来使输入起作用,同时在读取时将其丢弃。
不,你不需要这样做。只有当标准输入绑定到终端时,它才是行缓冲的。你可以运行prog < /dev/zero
或cat file | prog
。
你可能不想写入stdin
。有关详细信息,请参阅“Writing to stdin and reading from stdout”。
嗯,对于我来说,你要实现什么并不是很清楚。我假设你只是想按固定大小的块从stdin
读取数据。可以使用io.ReadFull来实现这一点。或者如果你想使用缓冲区,可以使用Reader.Peek或Scanner来确保特定数量的字节可用。我修改了你的程序以演示如何使用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
即可。
英文:
> I guess that I will need to have a protocol in which I send a \n to
> make the input work and at the same time discard it when reading it
No, you don't. Stdin is line-buffered only if it's bound to terminal. You can run your program prog < /dev/zero
or cat file | prog
.
> bufio.NewWriter(os.Stdin).Write(p)
You probably don't want to write to stdin
. See "Writing to stdin and reading from stdout" for details.
Well, it's not particular clear for me what you're trying to achieve. I'm assuming, that you just want to read data from stdin
by fixed-size chunks. Use io.ReadFull for this. Or if you want to use buffers, you can use Reader.Peek or Scanner to ensure, that specific number of bytes is available. I've changed your program to demonstrate the usage of 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)
}
}
You can easily split it in two programs and test it that way. Just change input
to os.Stdin
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论