如何从同一个io.Reader多次读取

问题描述 投票:18回答:4

我想使用包含图像的request.Body(type io.ReadCloser)

我不想使用ioutil.ReadAll(),因为我想将此主体直接写入文件以及想要解码它,所以我只想使用对内容的引用传递给进一步的函数调用,

我尝试创建多个读者实例,例如如下所示

package main

import (
    "io/ioutil"
    "log"
    "strings"
)


func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")
    a := &r
    b := &r
    log.Println(ioutil.ReadAll(*a))
    log.Println(ioutil.ReadAll(*b))

}

但在第二次调用中它总是导致nil

请帮助我如何为同一个读者传递多个单独的参考?

go reader
4个回答
39
投票

io.Reader被视为一条小溪。因此,你无法阅读两次。想象一下传入的TCP连接。你无法回避进入的最新情况。

但您可以使用io.TeeReader复制流:

package main

import (
    "bytes"
    "io"
    "io/ioutil"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")
    var buf bytes.Buffer
    tee := io.TeeReader(r, &buf)

    log.Println(ioutil.ReadAll(tee))
    log.Println(ioutil.ReadAll(&buf)) 
}

关于Go Playground的例子


4
投票

当你调用ReadAll时,它将清空缓冲区,因此第二次调用将始终不返回任何内容。你可以做的是保存ReadAll的结果并在你的函数中重用它。例如:

bytes, _ := ioutil.ReadAll(r);
log.Println(string(bytes))

1
投票

从技术上讲,在一个阅读器上,您无法多次阅读。

  • 即使你创建了不同的引用但是
  • 当你读一次它将是所有引用引用的同一个对象。
  • 所以你可以做的是阅读内容并将其存储在一个变量中。
  • 然后根据需要多次使用该变量。

这将打印两次。

package main

import (
    "io/ioutil"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")
    stringData, _ := ioutil.ReadAll(r)
    log.Println(stringData)
    log.Println(stringData)
}

1
投票

@TheHippo答案是正确的我只是想添加它(但无法添加它,因为我只有49个声誉:():首先使用TeeReader并在使用缓冲区之后重要信息,否则第二个缓冲区将为空。

© www.soinside.com 2019 - 2024. All rights reserved.