Create + Submit (via HTTP) .ZIP file without writing to disk?

I want to work with a ZIP file that is created on the fly, without having to write it to disk (I / O slows performance) and serve it via HTTP.

Here's how I first tried to do this:

func ZipServe(W http.ResponseWriter, R *http.Request) { buf := new(bytes.Buffer) writer := zip.NewWriter(buf) // for the sake of this demonstration, this is the data I will zip data := ioutil.ReadFile("randomfile.jpg") f, err := writer.Create("randomfile.jpg") if err != nil { fmt.Println(err) } _, err = f.Write(data) if err != nil { fmt.Println(err) } io.Copy(W, buf) err := writer.Close() if err != nil { fmt.Println(err) } } 

This is not good, since .ZIP becomes corrupt after loading. I believe the problem is with io.Copy; Should I use a different method?

+5
source share
2 answers

It seemed interesting to me, and only for testing the following occurred to me:

http://play.golang.org/p/JKAde2jbR3

 package main import ( "archive/zip" "bytes" "fmt" "io/ioutil" "log" "net/http" ) func zipHandler(w http.ResponseWriter, r *http.Request) { filename := "randomfile.jpg" buf := new(bytes.Buffer) writer := zip.NewWriter(buf) data, err := ioutil.ReadFile(filename) if err != nil { log.Fatal(err) } f, err := writer.Create(filename) if err != nil { log.Fatal(err) } _, err = f.Write([]byte(data)) if err != nil { log.Fatal(err) } err = writer.Close() if err != nil { log.Fatal(err) } w.Header().Set("Content-Type", "application/zip") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.zip\"", filename)) //io.Copy(w, buf) w.Write(buf.Bytes()) } func main() { http.HandleFunc("/zip", zipHandler) http.ListenAndServe(":8080", nil) } 

I just add some headers like Content-Type and Content-Disposition .

Also, instead of using io.Copy(w, buf) I write w.Write(buf.Bytes()) directly, wondering if this is better? probably a more experienced user can clarify this.

+2
source

Here is a slightly simpler method using io.Copy . It's probably not like using buffers for large file sizes, but it works for me:

 func handleZip(w http.ResponseWriter, r *http.Request) { f, err := os.Open("main.go") if err != nil { log.Fatal(err) } defer func() { if err := f.Close(); err != nil { log.Fatal(err) } }() // write straight to the http.ResponseWriter zw := zip.NewWriter(w) cf, err := zw.Create(f.Name()) if err != nil { log.Fatal(err) } w.Header().Set("Content-Type", "application/zip") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.zip\"", f.Name())) // copy the file contents to the zip Writer _, err = io.Copy(cf, f) if err != nil { log.Fatal(err) } // close the zip Writer to flush the contents to the ResponseWriter err = zw.Close() if err != nil { log.Fatal(err) } } 
+1
source

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


All Articles