2016-11-10 2 views
0

Ich versuche, Bytes einer Zip-Datei mit io.Pipe() -Funktion in Golang streamen. Ich benutze Pipe-Reader, um die Bytes jeder Datei in der ZIP zu lesen und streame sie dann aus und benutze den Pipe-Writer, um die Bytes in das Antwortobjekt zu schreiben.Laden Sie eine Zip-Datei mit io.Pipe() lesen/schreiben golang

Dies ist keine funktionierende Implementierung, sondern eine Struktur dessen, was ich versuche zu erreichen. Ich möchte nicht ioutil.ReadAll verwenden, da die Datei sehr groß sein wird und Pipe() hilft mir zu vermeiden, alle Daten in den Speicher zu bringen. Kann jemand mit einer funktionierenden Implementierung mit io.Pipe() helfen?

+1

Sie müssen die gesamte Datei lesen. 'zip.NewReader' nimmt einen' io.ReaderAt', den Sie mit einem Pipe nicht machen können. – JimB

+0

konnte nicht io.Copy (zipReader, w) verwenden? https://golang.org/pkg/io/#Copy –

+0

@ mh-cbon Ich bin nicht 100% sicher, aber nicht io.Copy einen Puffer darunter verwenden? Das wollte ich vermeiden. – psbits

Antwort

0

Ich habe es funktioniert mit golang io.Pipe(). Der PipeWriter schreibt Byte in die Pipe in Chunks und die PipeReader Reader vom anderen Ende. Der Grund für die Verwendung einer Go-Routine ist eine nicht blockierende Schreiboperation, während simultane Lesevorgänge in der Pipe stattfinden.

Hinweis: Es ist wichtig, den Pipe Writer zu schließen (w.Close()), um EOF im Stream zu senden, andernfalls wird der Stream nicht geschlossen.

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 

} 

Bitte lassen Sie mich wissen, wenn jemand eine andere Möglichkeit hat, es zu tun.

+0

Die Goroutine und die Pipe sind hier sinnlos. Sie lesen die Datei immer noch synchron und fügen einfach eine weitere Kopie ohne Grund hinzu. – JimB

+0

@JimB Können Sie erklären, wie ist die Injektion/Leitung hier sinnlos? Die Go-Routine veranlaßt den Pipe-Writer, in Blöcken zu schreiben und ohne den vom anderen Ende gelesenen Pipe-Reader zu blockieren. Ich stimme zu, es ist eine Art von Kopie, aber dann würde das nicht alle Daten auf einmal kopieren? Vielleicht könnte ich copyN verwenden. – psbits

+0

Jedes Lesen/Kopieren muss in Blöcken geschehen, also bin ich mir nicht sicher, was Sie mit "alle gleichzeitig" meinen. Was Sie hier haben, ist eine weniger effiziente Version von 'io.Copy', aber es ist nicht nötig, überhaupt zu kopieren, da' ioutil.ReadAll' sowieso die gesamte Datei in den Speicher liest, also benutzen Sie das einfach direkt. – JimB