How to read multiple times from same io.Reader

馋奶兔 提交于 2019-11-29 16:21:42

问题


I want to use request.Body(type io.ReadCloser) which is containing a image.

I dont want to use ioutil.ReadAll() as i want to write this body directly to the file as well as want to decode it, so i only want to use the reference to the content to pass to further function calls,

I tried creating multiple instances of reader for example shown below

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

}

but in second call it always results into nil.

Please help me how can i pass multiple separate reference for the same reader?


回答1:


io.Reader is treated like a stream. Because of this you cannot read it twice. Imagine the an incoming TCP connection. You cannot rewind the whats coming in.

But you can use the io.TeeReader to duplicate the stream:

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

Example on Go Playground

Edit: As @mrclx pointed out: You need to read from the TeeReader first, otherwise the buffer will be empty.




回答2:


When you call ReadAll it's going to empty the buffer, so the second call will always return nothing. What you could do is save the result of ReadAll and reuse that in your functions. For example:

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



回答3:


Technically, on one reader, you cannot read multiple times.

  • Even if you create different references but
  • when you read once it will be same object referred by all references.
  • so what you can do is read the content and store it in one variable.
  • Then use that variable as many times as you want.

This will print twice.

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



回答4:


@TheHippo answer is correct I just wanted to add this (but couldn't add it because I have only 49 reputation:( ): it's important that you use the TeeReader first and after you use the buffer where the info is copied otherwise the second buffer will be empty.



来源:https://stackoverflow.com/questions/39791021/how-to-read-multiple-times-from-same-io-reader

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!