web-dev-qa-db-fra.com

Comment lire plusieurs fois depuis le même io.Reader

Je veux utiliser request.Body(type io.ReadCloser) qui contient une image.

Je ne veux pas utiliser ioutil.ReadAll() car je veux écrire ce corps directement dans le fichier ainsi que le décoder, donc je veux seulement utiliser la référence au contenu pour passer à d'autres appels de fonction,

J'ai essayé de créer plusieurs instances de lecteur, par exemple ci-dessous

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

}

mais lors du deuxième appel, il résulte toujours en nil.

S'il vous plaît, aidez-moi comment puis-je transmettre plusieurs références distinctes pour le même lecteur?

21
Abhishek Soni

io.Reader est traité comme un flux. Pour cette raison, vous ne pouvez pas le lire deux fois. Imaginez une connexion TCP TCP entrante. Vous ne pouvez pas rembobiner ce qui arrive.

Mais vous pouvez utiliser le io.TeeReader pour dupliquer le flux:

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

Exemple sur Go Playground

40
TheHippo

Lorsque vous appelez ReadAll, cela va vider le tampon, donc le deuxième appel ne retournera toujours rien. Ce que vous pourriez faire, c'est enregistrer le résultat de ReadAll et le réutiliser dans vos fonctions. Par exemple:

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

@TheHippo est correcte, je voulais juste l'ajouter (mais je n'ai pas pu l'ajouter car je n'ai que 49 points de réputation :(): il est important que vous utilisiez d'abord le TeeReader et après avoir utilisé le tampon où les informations sont copiées, sinon la seconde le tampon sera vide.

1
mrclx

Techniquement, sur un seul lecteur, vous ne pouvez pas lire plusieurs fois.

  • Même si vous créez des références différentes mais
  • quand vous lirez une fois ce sera le même objet référencé par toutes les références.
  • vous pouvez donc lire le contenu et le stocker dans une variable.
  • Utilisez ensuite cette variable autant de fois que vous le souhaitez.

Cela s'imprimera deux fois.

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
Vijay Gurunanee