如何在Golang中压缩包含子目录或文件的目录?

时间:2016-06-16 21:40:33

标签: go zip

我知道这将与zip package有关我只是不知道我将如何实现这样的事情。

5 个答案:

答案 0 :(得分:5)

这里的解决方案使用Go的内置递归file-walker,因为到目前为止的最佳答案是实现了自己的file-walker:


此外,我今天在生成zip文件时发现了一些发现,这些发现可能会让其他人头疼:

  • w.Create(zippath)的参数不应以“ /”开头,并且应相对于zip根目录(也就是如果解压缩存档将创建的文件夹)。因此,顶级“ manifest.xml”文件应为w.Create("manifest.xml")。嵌套文件应为w.Create("a/b/c.css)。如果您要生成不良/令人惊讶的档案,请首先检查以确保您没有违反此规则。我的代码没有尝试执行此操作。
  • 某些规范(例如epub)希望文件以某种顺序排列,但Go的filepath.Walk将按词法顺序进行爬网。 (就此而言,到目前为止,我发现所有epub解析器在这里都是宽松的,从Caliber到macOS上的Books.app)。如果需要特定的命令,那么@LeTigre的ReadDir解决方案将使您可以在每个下降级别对文件进行排序。

package main

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

// Zips "./input" into "./output.zip"
func main() {
    file, err := os.Create("output.zip")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    w := zip.NewWriter(file)
    defer w.Close()

    walker := func(path string, info os.FileInfo, err error) error {
        fmt.Printf("Crawling: %#v\n", path)
        if err != nil {
            return err
        }
        if info.IsDir() {
            return nil
        }
        file, err := os.Open(path)
        if err != nil {
            return err
        }
        defer file.Close()

        // Ensure that `path` is not absolute; it should not start with "/".
        // This snippet happens to work because I don't use 
        // absolute paths, but ensure your real-world code 
        // transforms path into a zip-root relative path.
        f, err := w.Create(path)
        if err != nil {
            return err
        }

        _, err = io.Copy(f, file)
        if err != nil {
            return err
        }

        return nil
    }
    err = filepath.Walk("input", walker)
    if err != nil {
        panic(err)
    }
}

答案 1 :(得分:1)

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

package main

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

func main() {

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

    err := ZipFiles(output, files)
    if err != nil {
        log.Fatal(err)
    }

    log.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 {

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

        // Get the file information
        info, err := zipfile.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 = file

        // 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
        }
        if _, err = io.Copy(writer, zipfile); err != nil {
            return err
        }
    }
    return nil
}

答案 2 :(得分:0)

您可以使用为其编写的库:github.com/pierrre/archivefile/zip

答案 3 :(得分:0)

要手动执行此操作,您可以修改上面链接的代码:

ExampleZipWriter

给你一个简单的例子,它有很多缺陷,但可能很容易理解:

func ZipWriter() {
    baseFolder := "/Users/tom/Desktop/testing/"

    // Get a Buffer to Write To
    outFile, err := os.Create(`/Users/tom/Desktop/zip.zip`)
    if err != nil {
        fmt.Println(err)
    }
    defer outFile.Close()

    // Create a new zip archive.
    w := zip.NewWriter(outFile)

    // Add some files to the archive.
    addFiles(w, baseFolder, "")

    if err != nil {
        fmt.Println(err)
    }

    // Make sure to check the error on Close.
    err = w.Close()
    if err != nil {
        fmt.Println(err)
    }
}

我们使用它来递归迭代文件以生成文件夹:

func addFiles(w *zip.Writer, basePath, baseInZip string) {
    // Open the Directory
    files, err := ioutil.ReadDir(basePath)
    if err != nil {
        fmt.Println(err)
    }

    for _, file := range files {
        fmt.Println(basePath + file.Name())
        if !file.IsDir() {
            dat, err := ioutil.ReadFile(basePath + file.Name())
            if err != nil {
                fmt.Println(err)
            }

            // Add some files to the archive.
            f, err := w.Create(baseInZip + file.Name())
            if err != nil {
                fmt.Println(err)
            }
            _, err = f.Write(dat)
            if err != nil {
                fmt.Println(err)
            }
        } else if file.IsDir() {

            // Recurse
            newBase := basePath + file.Name() + "/"
            fmt.Println("Recursing and Adding SubDir: " + file.Name())
            fmt.Println("Recursing and Adding SubDir: " + newBase)

            addFiles(w, newBase, file.Name() + "/")
        }
    }
}

答案 4 :(得分:0)

一种ez目录压缩方式,您可以运行服务器命令:

out, err := exec.Command("zip", "-r", "-D", "ideaz.zip", ".idea/*").Output()

https://play.golang.org/p/Mn-HmUjm5q2