2016-11-10 1 views
0

J'essaie de diffuser des octets d'un fichier zip en utilisant la fonction io.Pipe() dans golang. J'utilise le lecteur de tuyaux pour lire les octets de chaque fichier dans le fichier zip, puis les diffuser et utiliser le graveur pour écrire les octets dans l'objet de réponse.Télécharger un fichier zip en utilisant io.Pipe() lecture/écriture golang

func main() { 
    r, w := io.Pipe() 
// go routine to make the write/read non-blocking 
    go func() { 

    defer w.Close() 

    bytes, err := ReadBytesforEachFileFromTheZip() 
    err := json.NewEncoder(w).Encode(bytes) 
    handleErr(err) 
    }() 

Ceci n'est pas une implémentation fonctionnelle mais une structure de ce que j'essaie d'atteindre. Je ne veux pas utiliser ioutil.ReadAll car le fichier va être très volumineux et Pipe() m'aidera à éviter de mettre toutes les données en mémoire. Quelqu'un peut-il aider avec une implémentation de travail en utilisant io.Pipe()?

+1

Vous devez lire tout le fichier. 'zip.NewReader' prend un' io.ReaderAt', ce que vous ne pouvez pas faire avec un Pipe. – JimB

+0

ne pouvait pas utiliser io.Copy (zipReader, w)? https://golang.org/pkg/io/#Copy –

+0

@ mh-cbon Je ne suis pas sûr à 100%, mais pas io.Copie utiliser un tampon en dessous? Je voulais éviter ça. – psbits

Répondre

0

Je l'ai fait fonctionner en utilisant golang io.Pipe(). Le Pipewriter écrit un octet sur le canal dans les morceaux et le lecteur pipeReader de l'autre extrémité. La raison de l'utilisation d'un go-routine est d'avoir une opération d'écriture non bloquante alors que des lectures simultanées se produisent depuis le tuyau.

Remarque: Il est important de fermer le graveur de tube (w.Ferme()) pour envoyer EOF sur le flux sinon il ne fermera pas le flux.

func DownloadZip() ([]byte, error) { 
    r, w := io.Pipe() 

    defer r.Close() 
    defer w.Close() 

    zip, err := os.Stat("temp.zip") 
    if err != nil{ 
     return nil, err 
    } 

    go func(){ 

     f, err := os.Open(zip.Name()) 
     if err != nil { 
      return 

     } 

     buf := make([]byte, 1024) 
     for { 
      chunk, err := f.Read(buf) 
      if err != nil && err != io.EOF { 
       panic(err) 
      } 
      if chunk == 0 { 
       break 
      } 

      if _, err := w.Write(buf[:chunk]); err != nil{ 
       return 
      } 

     } 

     w.Close() 
    }() 

    body, err := ioutil.ReadAll(r) 
    if err != nil { 
     return nil, err 
    } 
    return body, nil 

} 

Veuillez me faire savoir si quelqu'un d'autre a une autre façon de le faire.

+0

Le goroutine et le tuyau sont inutiles ici. Vous lisez toujours le fichier de manière synchrone, en ajoutant simplement une autre copie sans raison. – JimB

+0

@JimB Pourriez-vous expliquer en quoi le jointoiement/tuyau est inutile ici? La routine go fait écrire le pipe writer dans le pipe en morceaux et sans bloquer le lecteur de pipe lu de l'autre bout. Je suis d'accord pour dire que c'est une sorte de copie, mais cela ne copiera-t-il pas toutes les données à la fois? Peut-être que je pourrais utiliser copyN. – psbits

+0

Toute lecture/copie doit se faire en morceaux, donc je ne suis pas sûr de ce que vous entendez par "tout à la fois". Qu'est-ce que vous avez ici est une version moins efficace de 'io.Copy', mais il n'y a pas besoin de copier du tout puisque' ioutil.ReadAll' va lire le fichier entier en mémoire de toute façon, donc juste l'utiliser directement. – JimB