2017-10-17 114 views
5

我想提供一个即时创建的.ZIP文件,而不必将其写入磁盘(I/O会降低性能)并通过HTTP将其提供给客户端。创建+服务(通过HTTP).ZIP文件,而不写入磁盘?

这是我第一次尝试这样的:

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

} 

这是不行的,因为.ZIP最终被下载后损坏。我想这个问题与io.Copy有关;我应该使用不同的方法吗?

+1

您正在复制zip作家,然后关闭它。 – JimB

+0

@JimB什么是首选?,以'io.Copy(w,buf)'或'w.Write(buf.Bytes())' – nbari

+1

@nbari:因为我们知道'buf'是'bytes.Buffer '所以整个文件已经在一个切片中,我更喜欢第二个,因为我们在技术上不需要Copy调用。在实践中或者没有问题。 – JimB

回答

2

我发现有趣这一点,只是为了测试想出了这个:

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

我只是添加一些标题,如Content-TypeContent-Disposition

而不是使用io.Copy(w, buf)我直接写w.Write(buf.Bytes())想知道这是否更好?可能更有经验的用户可以澄清这一点。

1

这是一个使用io.Copy稍微简单一些的方法。这可能不像使用缓冲区来保存更大的文件大小,但它适用于我:

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) 
    } 
} 
相关问题