繁体   English   中英

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

[英]How to read multiple times from same io.Reader

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

我不想使用ioutil.ReadAll()因为我想将此正文直接写入文件并对其进行解码,所以我只想使用对内容的引用来传递给进一步的 function 调用,

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

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

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

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示例

编辑:正如@mrclx 指出的:您需要TeeReader读取,否则缓冲区将为空。

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

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

当您从 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))

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

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

这将打印两次。

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)
}

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

克隆Reader结构。

package main

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

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

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM