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

时间:2016-09-30 11:58:33

标签: go reader

我想使用包含图片的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

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

5 个答案:

答案 0 :(得分:34)

io.Reader被视为流。因此,你无法阅读两次。想象一下传入的TCP连接。你无法回避最近的事情。

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

    $ php composer.phar --version
    Composer version 1.2.1 2016-09-12 11:27:19

Go Playground

上的示例

答案 1 :(得分:3)

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

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

答案 2 :(得分: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)
}

答案 3 :(得分:1)

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

答案 4 :(得分:1)

从ioutil.ReadAll(r)中读取时,内容消失了。您无法第二次阅读。 例如:

var response *http.Response

//Read the content
rawBody, err := ioutil.ReadAll(response.Body)
    if err != nil {
        t.Error(err)
    }

// Restore the io.ReadCloser to it's original state
response.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody))