文章目录

  • 1.压缩
  • 2.解压缩
  • 3.进一步封装
    • 3.1 压缩
    • 3.2 解压
    • 3.3 go-huge-util
  • 参考文献

Go 和许多其他编程语言一样,支持从标准库中直接进行 zip 文件的压缩和解压。在本文中,我们将介绍如何在 Go 中利用标准库包 archive/zip 完成 zip 文件的创建和提取。

1.压缩

第一步:创建一个 zip 基础文件。

zip 文件也是一个文件,我们要做的第一件事是创建为一个简单的文件作为 zip 文件,就像在 Go 中处理任何其他文件一样。使用 os package 的 os.Create() 函数创建一个文件对象。

func Create(name string) (*File, error)

第二步:初始化 zip.Writer。

使用 archive/zip 包中的 zip.NewWriter 函数初始化一个 zip.Writer,用于将数据(文件和目录)写入 zip 文件。

func NewWriter(w io.Writer) *Writer

第三步:使用 zip.Writer.Create 创建一个 io.Writer。

一旦创建完 zip writer 后,便可以使用 zip.Writer.Create 向 zip 文件中添加一个文件或目录。它返回一个待压缩的文件内容应写入的 Writer,文件内容将使用 Deflate 方法进行压缩。

func (w *Writer) Create(name string) (io.Writer, error)

第四步:使用 io.Copy 或 io.Writer.Write 写数据到到 zip 文件。

zip.Writer.Create 函数返回一个 io.Writer ,因此任何文件内容都可以通过流式写入该 writer。使用 io.Copy 或调用 writer 的 Write 方法。

func Copy(dst Writer, src Reader) (written int64, err error)

第五步:使用 zip.Writer.Close 关闭 zip 文件。

将所有文件和目录写入 zip 文件后,可以通过 zip.Writer.Close 方法关闭 zip writer,将所有数据写入指向基础 zip 文件的数据流。注意,它不会关闭指向基础 zip 文件的 Writer。

func (w *Writer) Close() error

下面给出示例代码:

package mainimport ("archive/zip""fmt""io""os"
)func main() {fmt.Println("creating zip archive...")archive, err := os.Create("archive.zip")if err != nil {panic(err)}defer archive.Close()zipWriter := zip.NewWriter(archive)fmt.Println("opening first file...")f1, err := os.Open("test.csv")if err != nil {panic(err)}defer f1.Close()fmt.Println("writing first file to archive...")w1, err := zipWriter.Create("csv/test.csv")if err != nil {panic(err)}if _, err := io.Copy(w1, f1); err != nil {panic(err)}fmt.Println("opening second file")f2, err := os.Open("test.txt")if err != nil {panic(err)}defer f2.Close()fmt.Println("writing second file to archive...")w2, err := zipWriter.Create("txt/test.txt")if err != nil {panic(err)}if _, err := io.Copy(w2, f2); err != nil {panic(err)}fmt.Println("closing zip archive...")zipWriter.Close()
}

运行输出:

creating zip archive...
opening first file...
writing first file to archive...
opening second file
writing second file to archive...
closing zip archive...

最终的 zip 存档包含预期的文件。

unzip -l archive.zipArchive:  archive.zip
Length  Date  Time  Name
---------  ---------- ----- ----
57  00-00-1980 00:00 csv/test.csv
12  00-00-1980 00:00 txt/test.txt
--------- -------
69 2 files

2.解压缩

利用标准库 archive/zip 包可以创建 zip 文件,同样地也可以完成对 zip 文件的解压缩。下面让我们看看如何在 Go 中解压 zip 文件。

第一步:使用 zip.OpenReader 打开 zip 文件。

要想解压 zip 文件我们可能需要做的第一件事是打开它。我们可以使用 archive/zip 包提供的函数 zip.OpenReader 来打开 zip 文件,以 io.ReadCloser 的形式返回一个 zip.Reader 的实例。

func OpenReader(name string) (*ReadCloser, error)

第二步:循环访问 zip 中的文件。

zip.OpenReader 返回一个 zip.Reader 实例,其包含一个 zip.File 切片。

type Reader struct {File []*FileComment string// contains filtered or unexported fields
}

第三步:使用 zip.File.Open 方法读取 zip 中文件的内容。

func (f *File) Open() (io.ReadCloser, error)

第四步:使用 io.Copy 或 io.Writer.Write 保存解压后的文件内容。

func Copy(dst Writer, src Reader) (written int64, err error)

第五步:使用 zip.Reader.Close 关闭 zip 文件。

读取完 zip 存档中所有文件的内容并保存到指定位置后,要用接口 ReadCloser 中的方法 Close 关闭文件句柄。

type ReadCloser interface {ReaderCloser
}// Closer is the interface that wraps the basic Close method.
// The behavior of Close after the first call is undefined.
// Specific implementations may document their own behavior.
type Closer interface {Close() error
}

下面给出示例,我们尝试解压缩包含 2 个文件的 zip 文件。有一个 txt 文件和一个 csv 文件,它们将被解压缩到选定的输出目录中。

package mainimport ("archive/zip""fmt""io""os""path/filepath""strings"
)func main() {dst := "output"archive, err := zip.OpenReader("archive.zip")if err != nil {panic(err)}defer archive.Close()for _, f := range archive.File {filePath := filepath.Join(dst, f.Name)fmt.Println("unzipping file ", filePath)if !strings.HasPrefix(filePath, filepath.Clean(dst)+string(os.PathSeparator)) {fmt.Println("invalid file path")return}if f.FileInfo().IsDir() {fmt.Println("creating directory...")os.MkdirAll(filePath, os.ModePerm)continue}if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {panic(err)}dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())if err != nil {panic(err)}fileInArchive, err := f.Open()if err != nil {panic(err)}if _, err := io.Copy(dstFile, fileInArchive); err != nil {panic(err)}dstFile.Close()fileInArchive.Close()}
}

运行输出:

unzipping file  output/csv/test.csv
unzipping file  output/txt/test.txt

3.进一步封装

上面详细讲解了压缩与解压缩的操作,并给出了相应的示例。为了更好的复用上面的代码,下面做了进一步的封装,实现两个压缩与解压缩的函数。

3.1 压缩

// Zip compresses the specified files or dirs to zip archive.
// If a path is a dir don't need to specify the trailing path separator.
// For example calling Zip("archive.zip", "dir", "csv/baz.csv") will get archive.zip and the content of which is
// dir
// |-- foo.txt
// |-- bar.txt
// baz.csv
func Zip(zipPath string, paths ...string) error {// create zip fileif err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil {return err}archive, err := os.Create(zipPath)if err != nil {return err}defer archive.Close()// new zip writerzipWriter := zip.NewWriter(archive)defer zipWriter.Close()// traverse the file or directoryfor _, srcPath := range paths {// remove the trailing path separator if path is a directorysrcPath = strings.TrimSuffix(srcPath, string(os.PathSeparator))// visit all the files or directories in the treeerr = filepath.Walk(srcPath, func(path string, info fs.FileInfo, err error) error {if err != nil {return err}// create a local file headerheader, err := zip.FileInfoHeader(info)if err != nil {return err}// set compressionheader.Method = zip.Deflate// set relative path of a file as the header nameheader.Name, err = filepath.Rel(filepath.Dir(srcPath), path)if err != nil {return err}if info.IsDir() {header.Name += string(os.PathSeparator)}// create writer for the file header and save content of the fileheaderWriter, err := zipWriter.CreateHeader(header)if err != nil {return err}if info.IsDir() {return nil}f, err := os.Open(path)if err != nil {return err}defer f.Close()_, err = io.Copy(headerWriter, f)return err})if err != nil {return err}}return nil
}

如将一个目录和一个文件添加到当前目录指定名称的 zip 文件。

func main() {err := Zip("archive.zip", "dir", "baz.csv")fmt.Println("err is", err)
}

我们可以查看一下生成的 zip 文件的内容。

unzip -l archive.zipArchive:  archive.zipLength      Date    Time    Name
---------  ---------- -----   ----0  01-15-2022 20:17   dir/0  01-15-2022 20:17   dir/bar.txt0  01-15-2022 20:17   dir/foo.txt0  01-15-2022 20:30   baz.csv
---------                     -------0                     4 files

3.2 解压

// Unzip decompresses a zip file to specified directory.
// Note that the destination directory don't need to specify the trailing path separator.
func Unzip(zipPath, dstDir string) error {// open zip filereader, err := zip.OpenReader(zipPath)if err != nil {return err}defer reader.Close()for _, file := range reader.File {if err := unzipFile(file, dstDir); err != nil {return err}}return nil
}func unzipFile(file *zip.File, dstDir string) error {// create the directory of filefilePath := path.Join(dstDir, file.Name)if file.FileInfo().IsDir() {if err := os.MkdirAll(filePath, os.ModePerm); err != nil {return err}return nil}if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {return err}// open the filerc, err := file.Open()if err != nil {return err}defer rc.Close()// create the filew, err := os.Create(filePath)if err != nil {return err}defer w.Close()// save the decompressed file content_, err = io.Copy(w, rc)return err
}

比如将上面创建的 archive.zip 文件解压到当前目录。

func main() {err := Unzip("archive.zip", ".")fmt.Println("err is", err)
}

3.3 go-huge-util

以上函数已放置开源库 go-huge-util,可 import 直接使用。

package mainimport ("fmt"huge "github.com/dablelv/go-huge-util"
)func main() {_ := huge.Zip("archive.zip", "dir", "baz.csv")_ := huge.Unzip("archive.zip", ".")
}

欢迎大家 Star & PR。


参考文献

Golang Zip File Example
Golang Unzip File Example
Zip a file in Go
Unzip a file in Go

Golang zip 压缩与解压相关推荐

  1. 正确的 zip 压缩与解压代码

    网上流传的zip压缩与解压 的代码有非常大的问题 尽管使用了ant进行压缩与解压,可是任务的流程还是用的java.util.zip 的方式写的,我在使用的过程中遇到了压缩的文件夹结构有误,甚至出现不同 ...

  2. java 压缩 空目录_java zip压缩与解压-支持空目录,保留文件修改时间

    java zip压缩与解压-支持空目录,保留文件修改时间. 依赖于commons-io,commons-compress [Java]代码 import java.io.BufferedInputSt ...

  3. Linux中压缩和解压(gzip压缩/gunzip解压)(zip压缩/unzip解压)(tar打包解压)

    文章目录 Linux中压缩和解压(gzip压缩/gunzip解压)(zip压缩/unzip解压)(tar打包解压) 一.gzip压缩 / gunzip解压 1.命令 2.注意 3.案例 4.常用 二. ...

  4. 如何在 C# 中用 SharpZipLib 进行 ZIP 压缩与解压(转)

    转自:http://www.cftea.com/c/2008/04/A1FQ34RYSYNLFT47.asp SharpZipLib 是一个免费的组件,可以利用它对 ZIP 等多种格式进行压缩与解压. ...

  5. python zip压缩_Python zip压缩与解压(zipfile模块实例)

    python中提供了文件压缩的zipfile模块. zipfile模块() 用于压缩文件成zip及解压zip文件,模块介绍如下. zipfile.ZipFile(file, mode) open a ...

  6. Linux zip 压缩,解压

    Centos_7.9_2009 1. 压缩文件夹 zip -r docker-ce.zip docker-ce  -r :递归压缩 解压:unzip docker-ce.zip 2.加密压缩 zip ...

  7. Linux下zip压缩的解压

    1.unzip windows常见的压缩包有rar和zip格式,如果要将压缩包上传到Linux上再解压,就要使用unzip命令.以下是unzip常见命令: unzip a.zip # 解压到当前目录 ...

  8. go语言实现zip压缩与解压

    直接上代码 package utilsimport ("archive/zip""fmt""io""io/ioutil" ...

  9. 前端实现对ZIP 压缩文件解压,实现前端直接展示结果,比如图片,压缩包等 audio对象进行播放

    其中后台代码,很简单: /// <summary>/// 获取压缩的zip文件/// </summary>/// <returns></returns> ...

最新文章

  1. R语言使用ggplot2可视化互相覆盖的直方图实战(Overlaying histograms)
  2. 四川音乐学录音艺术与计算机音乐,艺考中作曲专业和录音专业有什么不同呢?...
  3. 材料模拟python_用Python模拟无限生成器
  4. jQuery ajax简单案例-验证用户名是否可用
  5. Unity 2017 Game Optimization 读书笔记 The Benefits of Batching
  6. java http请求插件_java http请求工具整理
  7. Recursive sequence HDU - 5950
  8. java 6大原则_java 6大设计原则 一:观察者模式
  9. sf | 空间矢量对象的几何信息处理方法
  10. PyTorch实战福利从入门到精通之二——Tensor
  11. 如何使用Python进行单元测试
  12. C#通用验证类:邮箱,电话,手机,数字,英文,日期,身份证,邮编,网址,IP
  13. jquery的Dom操作查找节点
  14. ubuntu nginx配置虚拟主机,目录
  15. 5G NR CSI Report中关于codebook/PMI的理解(1)
  16. 2021-2027年全球与中国彩色隐形眼镜行业市场前瞻与投资战略规划分析报告
  17. FBEC2020大会圆满闭幕!区块链分会场人气爆棚!
  18. 黑苹果SSDT修正关机/重启问题
  19. 【黑马程序员pink老师前端】网页相关概念
  20. 软件测试之补丁包测试

热门文章

  1. 俄罗斯黑客被指攻击本国的工业组织机构
  2. 「大学生学编程系列」第六篇:如何学习C语言?
  3. dubbo学习--导入eclipse异常Unbound classpath container(2)
  4. centos 实现ssh远程连接docker
  5. Python的那些隐藏特性
  6. R语言学习笔记:矩阵与数组(array)
  7. ExtJS4.2学习(11)——高级组件之Grid
  8. .NET Framework 1.1 中 SmartNavigation 的实现
  9. php web表格导出,javascript将web表格导出成excel
  10. [Java] 蓝桥杯ALGO-11 算法训练 瓷砖铺放