如何使用 Golang 将文件添加到现有的 zip 文件

How add a file to an existing zip file using Golang

我们可以创建一个 zip 新文件并使用 Go 语言添加文件。

但是,如何使用 GoLang 添加带有现有 zip 文件的新文件?

如果我们可以使用 Create 函数,如何获取 zip.writer 引用?

有点困惑。

经过更多分析,我发现无法使用现有的 zip 文件添加任何文件。

但是,我能够按照 this URL.

中给出的技巧添加带有 tar 文件的文件

虽然我还没有尝试使用已经存在的 zip 文件然后写入它,但我相信您应该能够向其中添加文件。

这是我编写的代码,用于创建包含多个文件的综合 zip 文件,以便加快将数据上传到另一个位置的速度。希望对您有所帮助!

type fileData struct {
    Filename string
    Body     []byte
}

func main() {
    outputFilename := "path/to/file.zip"

    // whatever you want as filenames and bodies
    fileDatas := createFileDatas()

    // create zip file
    conglomerateZip, err := os.Create(outputFilename)
    if err != nil {
        return err
    }
    defer conglomerateZip.Close()

    zipWriter := zip.NewWriter(conglomerateZip)
    defer zipWriter.Close()

    // populate zip file with multiple files
    err = populateZipfile(zipWriter, fileDatas)
    if err != nil {
        return err
    }

}

func populateZipfile(w *zip.Writer, fileDatas []*fileData) error {
    for _, fd := range fileDatas {
        f, err := w.Create(fd.Filename)
        if err != nil {
            return err
        }

        _, err = f.Write([]byte(fd.Body))
        if err != nil {
            return err
        }

        err = w.Flush()
        if err != nil {
            return err
        }
    }
    return nil
}

这有点旧,已经有了答案,但如果性能不是您的主要关注点(例如,使 zip 文件不在热路径上),您可以 使用 archive/zip 库执行此操作,方法是创建一个新编写器并将现有文件复制到其中,然后添加新内容。像这样:

zw := // new zip writer from buffer or temp file
newFileName := // file name to add
reader, _ := zip.NewReader(bytes.NewReader(existingFile), int64(len(existingFile)))
for _, file := range reader.File {
    if file.Name == newFileName {
        continue // don't copy the old file over to avoid duplicates
    }
    fw, _ := zw.Create(file.Name)
    fr, _ := file.Open()
    io.Copy(fw, fr)
    fr.Close()
}

然后您将 return 新编写器并根据需要追加文件。如果您不确定哪些文件可能重叠,您可以将其 if check 转换为一个包含您最终将添加的文件名列表的函数。您还可以使用此逻辑从现有存档中删除文件。

您可以:

  1. 将旧的 zip 项目复制到新的 zip 文件中;
  2. 将新文件添加到新的 zip 文件中;
zipReader, err := zip.OpenReader(zipPath)
targetFile, err := os.Create(targetFilePath)
targetZipWriter := zip.NewWriter(targetFile)

for _, zipItem := range zipReader.File {
    zipItemReader, err := zipItem.Open()
    header, err := zip.FileInfoHeader(zipItem.FileInfo())
    header.Name = zipItem.Name
    targetItem, err := targetZipWriter.CreateHeader(header)
    _, err = io.Copy(targetItem, zipItemReader)
}

addNewFiles(targetZipWriter) // IMPLEMENT YOUR LOGIC

现在 2021 年,仍然不支持将文件附加到现有存档。 但至少现在可以添加已经压缩的文件,即我们在将文件从旧存档复制到新存档时不再需要解压缩和重新压缩文件。

(注意: 这仅适用于 Go 1.17+)

因此,基于@wongoo 和@Michael 的示例,以下是我现在如何以最小的性能开销实现附加文件(尽管您会想要添加错误处理):

zr, err := zip.OpenReader(zipPath)
defer zr.Close()
zwf, err := os.Create(targetFilePath)
defer zwf.Close()
zw := zip.NewWriter(zwf)
defer zwf.Close() // or not... since it will try to wrote central directory

for _, zipItem := range zrw.File {
    if isOneOfNamesWeWillAdd(zipItem.Name) {
        continue // avoid duplicate files!
    }
    zipItemReader, err := zipItem.OpenRaw()
    header := zipItem.FileHeader // clone header data
    targetItem, err := targetZipWriter.CreateRaw(&header) // use cloned data
    _, err = io.Copy(targetItem, zipItemReader)
}

addNewFiles(zw) // IMPLEMENT YOUR LOGIC