我想要提供即时创建的.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有关;我应该使用不同的方法吗?
答案 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-Type
和Content-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)
}
}