创建+服务(通过HTTP).ZIP文件,而无需写入磁盘?

时间:2017-10-17 13:17:21

标签: http go zip

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

以下是我首次尝试此操作的方法:

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有关;我应该使用不同的方法吗?

2 个答案:

答案 0 :(得分:9)

我觉得这很有趣,只是为了测试得出了这个:

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 :(得分:3)

这是使用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)
    }
}
相关问题