为什么在读取完io.Reader后它会变为空?

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

Why does an io.reader become empty after reading it?

问题

func foo(buf *bytes.Buffer) {
fmt.Println("0: ", len(buf.Bytes()))
ioutil.ReadAll(buf)
fmt.Println("1: ", len(buf.Bytes()))
}

这段代码第一次显示了正确的长度,但第二次显示长度为零。

英文:
func foo(buf *bytes.Buffer) {
    fmt.Println("0: ", len(buf.Bytes()))
    ioutil.ReadAll(buf)
    fmt.Println("1: ", len(buf.Bytes()))
}

The code shows the correct length the first time, but the second times it shows the length is zero.

答案1

得分: 10

bytes.Buffer中读取会消耗或使用已读取的字节。这意味着如果你尝试再次读取,这些字节将不会被返回。

Buffer.Bytes()返回缓冲区中未读取的部分,所以在所有内容都被读取后,你会看到长度为0的结果(这正是ioutil.ReadAll()的作用)。


如果你只想“窥视”而不是真正“读取”字节,该怎么办?

bytes.Buffer中没有“窥视”功能。最简单的方法是获取缓冲区的字节,并从中构建另一个bytes.Buffer来进行读取。

代码可能如下所示:

func peek(buf *bytes.Buffer, b []byte) (int, error) {
    buf2 := bytes.NewBuffer(buf.Bytes())
    return buf2.Read(b)
}

peek()的使用示例:

为简单起见,省略了错误检查:

buf := &bytes.Buffer{}

buf.WriteString("Hello")
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

fmt.Println("\nPeeking...")
data := make([]byte, 4)
peek(buf, data)
fmt.Printf("Peeked: %s\n", data)
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

fmt.Println("\nReading...")
data = make([]byte, buf.Len())
buf.Read(data)
fmt.Printf("Read: %s\n", data)
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

输出结果(在Go Playground上尝试):

Len: 5, Content: Hello

Peeking...
Peeked: Hell
Len: 5, Content: Hello

Reading...
Read: Hello
Len: 0, Content: 
英文:

Reading from a bytes.Buffer drains or consumes the bytes that were read. This means if you try to read again, those will not be returned.

Buffer.Bytes() returns the unread portion of the buffer, so it is the expected result for you to see 0 length after everything has been read (this is exactly what ioutil.ReadAll() does).


What if you just want to "peek" and not really "read" bytes?

There is no "peek" functionality in bytes.Buffer. The easiest would be to get the bytes of the buffer, and construct another bytes.Buffer from it and read from the new buffer.

It could look something like this:

func peek(buf *bytes.Buffer, b []byte) (int, error) {
    buf2 := bytes.NewBuffer(buf.Bytes())
    return buf2.Read(b)
}

peek() in action:

Error checks omitted for simplicity:

buf := &bytes.Buffer{}

buf.WriteString("Hello")
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

fmt.Println("\nPeeking...")
data := make([]byte, 4)
peek(buf, data)
fmt.Printf("Peeked: %s\n", data)
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

fmt.Println("\nReading...")
data = make([]byte, buf.Len())
buf.Read(data)
fmt.Printf("Read: %s\n", data)
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

Output (try it on the Go Playground):

Len: 5, Content: Hello

Peeking...
Peeked: Hell
Len: 5, Content: Hello

Reading...
Read: Hello
Len: 0, Content: 

huangapple
  • 本文由 发表于 2015年6月18日 16:43:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/30910487.html
匿名

发表评论

匿名网友

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

确定