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

Abh*_*oni 24 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))

}
Run Code Online (Sandbox Code Playgroud)

但在第二次通话中它总会产生nil.

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

The*_*ppo 44

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)) 
}
Run Code Online (Sandbox Code Playgroud)

Go Playground上的示例

  • 另外,如果流的数据很大 - 例如“1GB” - 不要使用“ReadAll”。相反 - 由于OP希望首先将其写入文件 - 使用 `err, _ := io.Copy(fh, tee)` (3认同)

San*_*njX 13

当您从 ioutil.ReadAll(r) 读取时,内容就消失了。您无法\xe2\x80\x99 再次读取它。\n例如:

\n\n
var response *http.Response\n\n//Read the content\nrawBody, err := ioutil.ReadAll(response.Body)\n    if err != nil {\n        t.Error(err)\n    }\n\n// Restore the io.ReadCloser to it's original state\nresponse.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody))\n
Run Code Online (Sandbox Code Playgroud)\n


lau*_*ent 8

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

bytes, _ := ioutil.ReadAll(r);
log.Println(string(bytes))
Run Code Online (Sandbox Code Playgroud)

  • 如果读取器包含非常大的数据(例如 2G 再见),则这是一个不好的方法。 (3认同)