2017-10-17 85 views
5

Ben diske yazmak zorunda kalmadan (I/O performans yavaşlatır) ve HTTP üzerinden istemciye sunmak, anında oluşturulan bir .ZIP dosya sunmak istiyorum. .ZIP indirdikten sonra bozuk olmak biter gibi bu hiç iyi değilDiske yazmadan + Hizmet (HTTP üzerinden) bir .ZIP dosyası oluşturun?

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

} 

: Burada

Öncelikle bu teşebbüs nasıl. Sanırım sorun io.Copy ile ilgisi var; Farklı bir yöntem mi kullanmalıyım?

+1

Kapatmadan önce zip yazarını kopyalıyorsunuz. – JimB

+0

@JimB tercih edilen nedir ?, io.Copy (w, buf) 'veya' w.Write (buf.Bytes()) ' – nbari

+1

@nbari: Bildiğimiz günden beri buf' bir bytes.Buffer 'tüm dosya zaten bir dilim içinde, teknik olarak Copy çağrısına gerek duymadığımızdan ikincisini tercih ederim. Pratikte ya iyi. – JimB

cevap

2

bu ilginç buldum ve sadece test için bu geldi:

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

Sadece Content-Type ve Content-Disposition gibi bazı başlıkları ekleyin.

Ayrıca, io.Copy(w, buf) kullanmak yerine, daha iyi olup olmadığını merak ederek doğrudan w.Write(buf.Bytes()) yazıyorum. Muhtemelen daha deneyimli bir kullanıcı bunu açıklayabilir.

1

io.Copy kullanarak biraz daha basit bir yöntem. Büyük dosya boyutları için bir arabellek kullanmak kadar verimli değildir, ancak benim için çalışır:

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