How to read several times from one io.Reader

I want to use request.Body(type io.ReadCloser) , which contains the image.

I do not want to use ioutil.ReadAll() , because I want to write this body directly to a file, and I also want to decode it, so I want to use the link to the content for subsequent function calls,

I tried to create multiple instances of the reader, such as those 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 the second call it is always output in nil .

Please help me, how can I pass several separate links for the same reader?

+22
source share
4 answers

io.Reader treated as a stream. Because of this, you cannot read it twice. Imagine an inbound TCP connection. You cannot rewind what is happening.

But you can use 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)) } 

Go Playground Example

Edit: As @mrclx noted: First you need to read from TeeReader , otherwise the buffer will be empty.

+42
source

When you call ReadAll , it will be an empty buffer, so the second call always returns nothing. What you can do is save the ReadAll result and reuse it in your functions. For instance:

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

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

  • Even if you create different links , but
  • when you read once, when it will be the same object that all links link to.
  • so you can read the contents and save it in one variable.
  • Then use this variable as many times as you want.

This will be printed 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) } 
+1
source

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

+1
source

Source: https://habr.com/ru/post/1257520/


All Articles