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

huangapple go评论81阅读模式
英文:

How add a file to an existing zip file using Golang

问题

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

但是,如何使用Go语言向现有的zip文件中添加新文件呢?

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

有点困惑。

英文:

We can create a zip new file and add files using Go Language.

But, how to add a new file with existing zip file using GoLang?

If we can use Create function, how to get the zip.writer reference?

Bit confused.

答案1

得分: 4

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

但是,我通过按照这个网址中给出的方法,成功向tar文件中添加了文件。

英文:

After more analysis, i found that, it is not possible to add any files with the existing zip file.

But, I was able to add files with tar file by following the hack given in this URL.

答案2

得分: 2

你可以:

  1. 将旧的压缩文件项复制到一个新的压缩文件中;
  2. 将新文件添加到新的压缩文件中;
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) // 实现你的逻辑
英文:

you can:

  1. copy old zip items into a new zip file;
  2. add new files into the new zip file;
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

答案3

得分: 1

尽管我尚未尝试过使用已存在的zip文件并向其写入文件,但我认为你应该能够向其中添加文件。

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

type fileData struct {
    Filename string
    Body     []byte
}

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

    // 你可以根据需要设置文件名和内容
    fileDatas := createFileDatas()

    // 创建zip文件
    conglomerateZip, err := os.Create(outputFilename)
    if err != nil {
        return err
    }
    defer conglomerateZip.Close()

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

    // 向zip文件中添加多个文件
    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
}

希望对你有帮助!

英文:

Although I have not attempted this yet with a zip file that already exists and then writing to it, I believe you should be able to add files to it.

This is code I have written to create a conglomerate zip file containing multiple files in order to expedite uploading the data to another location. I hope it helps!

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

得分: 1

这是一个有点旧的问题,已经有了答案,但如果性能不是你关注的重点(例如,创建zip文件不是一个热点路径),你可以使用archive/zip库来实现这个功能。你可以创建一个新的writer,并将现有文件复制到其中,然后添加你的新内容。代码示例如下:

zw := // 从缓冲区或临时文件创建新的zip writer
newFileName := // 要添加的文件名
reader, _ := zip.NewReader(bytes.NewReader(existingFile), int64(len(existingFile)))
for _, file := range reader.File {
    if file.Name == newFileName {
        continue // 不复制旧文件,以避免重复
    }
    fw, _ := zw.Create(file.Name)
    fr, _ := file.Open()
    io.Copy(fw, fr)
    fr.Close()
}

然后,你可以返回新的writer,并根据需要追加文件。如果你不确定哪些文件可能会重叠,你可以将if检查转换为一个函数,该函数包含你最终要添加的文件名列表。你也可以使用这个逻辑从现有的存档中删除文件。

英文:

This is a bit old and already has an answer, but if performance isn't a key concern for you (making the zip file isn't on a hot path for example) you can do this with the archive/zip library by creating a new writer and copying the existing files into it then adding your new content. Something like this:

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()
}

Then you would return the new writer and append files as needed. If you aren't sure which files might overlap you can turn that if check into a function with a list of file names you will eventually add. You can also use this logic to remove a file from an existing archive.

答案5

得分: 0

现在是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() // 或者不关闭...因为它会尝试写入中央目录

for _, zipItem := range zrw.File {
    if isOneOfNamesWeWillAdd(zipItem.Name) {
        continue // 避免重复文件!
    }
    zipItemReader, err := zipItem.OpenRaw()
    header := zipItem.FileHeader // 克隆头部数据
    targetItem, err := targetZipWriter.CreateRaw(&header) // 使用克隆的数据
    _, err = io.Copy(targetItem, zipItemReader)
}

addNewFiles(zw) // 实现您的逻辑
英文:

Now in 2021, there is still no support for appending files to an existing archive.
But at least it is now possible to add already-compressed files, i.e. we don't anymore have to decompress & re-compress files when duplicating them from old archive to new one.

(NOTE: this only applies to Go 1.17+)

So, based on examples by @wongoo and @Michael, here is how I would implement appending files now with the minimum performance overhead (you'll want to add error handling though):

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

huangapple
  • 本文由 发表于 2015年2月14日 15:26:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/28513486.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定