首页 > 解决方案 > 如何在 Go 中将文件压缩为没有目录文件夹的 .zip

问题描述

有一些关于在 Go 中将文件压缩为 .zip 的示例。但是,它们生成的文件包括目录文件夹。当我解压 .zip 文件时,会有一个新文件夹。

那么,如何在不包含目录文件夹的情况下将文件压缩为 .zip?

一个例子:

https://golangcode.com/create-zip-files-in-go/

package main

import (
    "archive/zip"
    "fmt"
    "io"
    "os"
)

func main() {

    // List of Files to Zip
    files := []string{"example.csv", "data.csv"}
    output := "done.zip"

    if err := ZipFiles(output, files); err != nil {
        panic(err)
    }
    fmt.Println("Zipped File:", output)
}

// ZipFiles compresses one or many files into a single zip archive file.
// Param 1: filename is the output zip file's name.
// Param 2: files is a list of files to add to the zip.
func ZipFiles(filename string, files []string) error {

    newZipFile, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer newZipFile.Close()

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

    // Add files to zip
    for _, file := range files {
        if err = AddFileToZip(zipWriter, file); err != nil {
            return err
        }
    }
    return nil
}

func AddFileToZip(zipWriter *zip.Writer, filename string) error {

    fileToZip, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer fileToZip.Close()

    // Get the file information
    info, err := fileToZip.Stat()
    if err != nil {
        return err
    }

    header, err := zip.FileInfoHeader(info)
    if err != nil {
        return err
    }

    // Using FileInfoHeader() above only uses the basename of the file. If we want
    // to preserve the folder structure we can overwrite this with the full path.
    header.Name = filename

    // Change to deflate to gain better compression
    // see http://golang.org/pkg/archive/zip/#pkg-constants
    header.Method = zip.Deflate

    writer, err := zipWriter.CreateHeader(header)
    if err != nil {
        return err
    }
    _, err = io.Copy(writer, fileToZip)
    return err
}

标签: gozip

解决方案


只需在 zip 标头中使用文件的基本名称即可。

header.Name = filepath.Base(filename)
              ^^^^^^^^^^^^^^

这是一个做同样事情的版本

package main

import (
    "archive/zip"
    "io"
    "log"
    "os"
    "path/filepath"
)

func createFlatZip(w io.Writer, files ...string) error {
    z := zip.NewWriter(w)
    for _, file := range files {
        src, err := os.Open(file)
        if err != nil {
            return err
        }
        info, err := src.Stat()
        if err != nil {
            return err
        }
        hdr, err := zip.FileInfoHeader(info)
        if err != nil {
            return err
        }
        hdr.Name = filepath.Base(file) // Write only the base name in the header
        dst, err := z.CreateHeader(hdr)
        if err != nil {
            return err
        }
        _, err = io.Copy(dst, src)
        if err != nil {
            return err
        }
        src.Close()
    }
    return z.Close()
}

func main() {
    if len(os.Args) < 3 {
        log.Fatalf("archive name and at least one file are required")
    }
    a, err := os.Create(os.Args[1])
    if err != nil {
        log.Fatal(err)
    }
    defer a.Close()

    err = createFlatZip(a, os.Args[2:]...)
    if err != nil {
        log.Fatal(err)
    }
}

结果:

~/src/gozip
➜ 去建造

~/src/gozip
➜ mkdir test && echo 1 > test/1.txt # 在子文件夹中创建一个测试文件

~/src/gozip
➜ ./gozip 1.zip 测试/1.txt

~/src/gozip
➜ 解压 -l 1.zip
存档:1.zip
  长度 日期 时间 名称
--------- ---------- ----- ----
        2 2019 年 8 月 15 日 01:29 1.txt
--------- -----
        2 1 个文件

推荐阅读