【问题标题】:How add a file to an existing zip file using Golang如何使用 Golang 将文件添加到现有的 zip 文件
【发布时间】:2015-02-14 07:26:58
【问题描述】:

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

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

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

有点困惑。

【问题讨论】:

  • 似乎不支持此功能。您可能需要提交功能请求以支持此功能。
  • 除了我需要的本地存档/zip 包之外,还有什么关于在 GoLang 中使用 zip 文件的建议吗?
  • 调用zip 命令行实用程序。
  • 不推荐调用 zip 命令行工具。因为,我正在尝试在应用程序中完成所有工作,并希望避免对 3rd 方工具的任何依赖。此外,我的应用程序在多个操作系统上运行,我不愿意为这个要求保留不同的工具。有没有比内置归档/压缩包更好的选择?
  • 我不知道。您可能想编写自己的绑定到现有的 zip 库。

标签: go zip


【解决方案1】:

你可以:

  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

【讨论】:

    【解决方案2】:

    这有点老了,已经有了答案,但如果性能不是您关心的关键问题(例如,使 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()
    }
    

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

    【讨论】:

      【解决方案3】:

      虽然我还没有尝试使用已经存在的 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
      }
      

      【讨论】:

        【解决方案4】:

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

        但是,我可以按照this URL 中给出的 hack 来添加带有 tar 文件的文件。

        【讨论】:

        【解决方案5】:

        现在是 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多