Reading from stdin in golang

huangapple go评论75阅读模式
英文:

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/zerocat file | prog

你可能不想写入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即可。

英文:

> 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 &lt; /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 (
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;time&quot;
)

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

	go func() {
		defer output.Close()
		for _, m := range []byte(&quot;123456&quot;) {
			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.

huangapple
  • 本文由 发表于 2015年3月15日 21:07:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/29060922.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定