前言

近来有个需求,需要从 zip 中提取一个文件出来,因为只用到其中的一个,其它的用不到,如果全部提取出来就有点多余了,在经过一番摸索发现还真可以。

实现

Go 标准库里有 archive/zip 这个包,所以我们可以直接使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import (
    "archive/zip"
    "io"
    "log"
    "os"
)

func main() {
    f, err := zip.OpenReader("test.zip") // 打开zip文件
    if err != nil {
        log.Println("open zip err: ", err)
        return
    }
    defer f.Close()
    testFile, err := f.Open("test.txt") // 打开zip中的test.txt,这里需要使用相对路径,如果你打开的是 test下的text.txt,则这里要传入 test/test.txt
    if err != nil {
        log.Println("open test.txt err: ", err)
        return
    }
    defer testFile.Close()
    dst, err := os.Create("test.txt") // 创建一个文件用来存放解压出来的内容
    defer dst.Close()
    _, err = io.Copy(dst, testFile) // 把内容复制到目标文件中
    if err != nil {
        log.Println("提取 test.txt失败: ", err)
        return
    }
    log.Println("提取 test.txt成功")

}

提取一个文件的步骤

  1. 使用 zip.OpenReader 打卡一个 zip 文件
  2. 然后使用 Open 打开 zip 中的文件
  3. 把内容拷贝出来

提取所有压缩文件

讲了提取 zip 中的一个文件,顺便给出提取所有文件的版本。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import (
    "archive/zip"
    "io"
    "log"
    "os"
    "path/filepath"
)

func main() {
    r, err := zip.OpenReader("test.zip")
    if err != nil {
        log.Fatal(err)
    }
    defer r.Close()

    for _, f := range r.File {
        if f.FileInfo().IsDir() {
            os.MkdirAll(f.Name, os.ModePerm)
        } else {
            if err = os.MkdirAll(filepath.Dir(f.Name), os.ModePerm); err != nil {
                log.Fatalln("mkdir failed:", f.Name, err)
                return
            }
            zf, err := f.Open()
            if err != nil {
                log.Fatalln("open zip file", f.Name, "failed")
                return
            }
            defer zf.Close()
            outFile, err := os.OpenFile(f.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
            if err != nil {
                log.Fatalln("create file", f.Name, "failed")
                return
            }
            defer outFile.Close()

            _, err = io.Copy(outFile, zf)
            if err != nil {
                log.Fatalln("copy failed ", err)
                return
            }
        }
    }
}

总结

go 语言实现解压的功能还是非常简单的,标准库就提供了解压的功能。

参考