dousou1878 2019-04-11 02:07 采纳率: 0%
浏览 101
已采纳

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

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 2019-04-11 02:28
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?