Zip-папка повреждена при использовании буфера в качестве вывода - PullRequest
0 голосов
/ 11 апреля 2019

Я пытаюсь записать 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 ()..

Любое направление для решения этой проблемы будет оценено.

1 Ответ

3 голосов
/ 11 апреля 2019

Вы читаете буфер до того, как закроете zip.Writer, поэтому любые окончательные данные должны быть сброшены, чтобы буфер был потерян.Вы должны удалить defer archive.Close() и вместо этого закрыть архив, прежде чем вывести байты из буфера.Например,

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

Это работает в вашем случае с файлом, потому что вы откладываете закрытие файла.Отсрочка будет применена последней в очереди, поэтому архив закрывается до закрытия файла.

...