dousou1878
dousou1878
2019-04-11 02:07

使用缓冲区作为输出时,压缩的文件夹已损坏

已采纳

I'm trying to write the zip file to a buffer instead of a file to eventually pass it to the http response. Below is the code to simulate that.

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
}

However the output of this zip process is corrupted. If I use a file instead of a buffer it works thought.

zipfile, err := os.Create(target)
if err != nil {
    return err
}
defer zipfile.Close()

archive := zip.NewWriter(zipfile)
defer archive.Close()

Both os.File and bytes.Buffer implements io.Writer interface and eligible to be passed as a writer to zip.NewWrite() method.

Any direction to solve this would be appreciated.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • dousenjue3214 dousenjue3214 2年前

    You read the buffer before you've closed the zip.Writer, so any final data is needs to flush to the buffer has gotten lost. You should remove the defer archive.Close() and instead close the archive before getting the bytes out of the buffer. e.g.

        err = archive.Close()
        return buf.Bytes(), err
    

    It works in your file case because you defer closing the file. The defer's will be applied last in first out, so the archive gets closed before the file is closed.

    点赞 评论 复制链接分享