如何从同一个输入输出读取多次。读取器

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

请帮助我如何才能通过多个不同的参考为同一读者?

45308 次浏览

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

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

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

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

这将打印两次。

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

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

去游乐场的例子

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

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

克隆 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))


}