为啥 io.reader 读完后会变空?
Posted
技术标签:
【中文标题】为啥 io.reader 读完后会变空?【英文标题】:Why does an io.reader become empty after reading it?为什么 io.reader 读完后会变空? 【发布时间】:2015-09-03 19:18:12 【问题描述】:func foo(buf *bytes.Buffer)
fmt.Println("0: ", len(buf.Bytes()))
ioutil.ReadAll(buf)
fmt.Println("1: ", len(buf.Bytes()))
代码第一次显示正确的长度,但第二次显示长度为零。
【问题讨论】:
【参考方案1】:从bytes.Buffer
读取会耗尽或消耗已读取的字节。这意味着如果您再次尝试阅读,这些内容将不会被返回。
Buffer.Bytes()
返回缓冲区的 unread 部分,因此在读取所有内容后看到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:
【讨论】:
非常感谢。我明白。是否有任何方法可以第二次阅读其内容? 这种方法不会复制任何东西(除了b中的数据),只是创建一个新的缓冲区。我可以看到这更快的唯一方法是执行“return copy(buf.Bytes(),b),nil”,它具有相同的效果但不分配新的缓冲区。不确定哪个实际上更快。 (猜测副本是) @DavidBudworth 是的,你是对的。Buffer.Bytes()
只返回一个共享相同底层数组的切片。所以在性能方面一点也不差。
对于可能还没有Buffer.Bytes()
中的所有数据的网络缓冲区使用这种方法似乎存在问题。
@Xeoncross bytes.Buffer
是一个内存缓冲区,它与网络无关。在网络的情况下,我们必须负责“重放”读取和检查的数据。可以在此答案中找到一个示例:Golang read request body以上是关于为啥 io.reader 读完后会变空?的主要内容,如果未能解决你的问题,请参考以下文章