goreader

How to read multiple times from same io.Reader


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?


Solution

  • io.Reader is treated like a stream. Because of this you cannot read it twice. Imagine an incoming TCP connection - you cannot rewind what's 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.