我试图将zip文件而不是文件写入缓冲区,以最终将其传递给http响应。下面是模拟该代码的代码。
package main
import (
"archive/zip"
"bytes"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
func main() {
data, err := zipit("myfolder")
if err != nil {
panic(err)
}
ioutil.WriteFile("output.zip", data, os.ModePerm)
}
func zipit(source string) ([]byte, error) {
buf := new(bytes.Buffer)
archive := zip.NewWriter(buf)
defer archive.Close()
info, err := os.Stat(source)
if err != nil {
return nil, nil
}
var baseDir string
if info.IsDir() {
baseDir = filepath.Base(source)
}
filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
if baseDir != "" {
header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
}
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if info.IsDir() {
return nil
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
return err
})
return buf.Bytes(), err
}
但是,此zip进程的输出已损坏。如果我使用文件而不是缓冲区,它会起作用。
zipfile, err := os.Create(target)
if err != nil {
return err
}
defer zipfile.Close()
archive := zip.NewWriter(zipfile)
defer archive.Close()
os.File和bytes.Buffer都实现io.Writer接口,并且可以作为编写器传递给zip.NewWrite()方法。
任何解决此问题的方向都将不胜感激。
答案 0 :(得分:3)
在关闭zip.Writer之前,您已经阅读了缓冲区,因此需要刷新到缓冲区的所有最终数据都丢失了。您应该删除defer archive.Close()
并关闭存档,然后再将字节移出缓冲区。例如
err = archive.Close()
return buf.Bytes(), err
它适用于您的文件情况,因为您推迟关闭文件。延迟将采用先进先出的方式,因此归档文件会在文件关闭之前被关闭。