在 Go (Golang) 中处理 ZIP 归档:完整指南
在现代 Go (Golang) 开发中,处理归档是一项常见任务。无论是打包日志、上传文件到服务器还是创建备份——标准库 archive/zip 提供了创建、读取和修改 ZIP 归档所需的一切,无需安装第三方依赖。在本文中,我们将通过实际示例介绍 Go 中 ZIP 的基本操作。
archive/zip 包的主要功能
archive/zip 包是 Go 标准库的一部分,支持:
- 创建具有任意文件夹结构的新 ZIP 归档
- 读取现有归档的内容
- 提取单个文件或整个归档
- 向现有归档添加文件(通过复制)
- 处理文件元数据(日期、权限、注释)
- 流式处理(无需将整个归档加载到内存中)
在 Go 中创建 ZIP 归档
要创建归档,使用 zip.NewWriter(),它接受一个 io.Writer。这允许将归档写入文件或缓冲区(例如,用于通过 HTTP 发送)。
package main
import ( "archive/zip" "bytes" "fmt" "io" "log" "os")
func createZip() { // 为归档创建缓冲区 buf := new(bytes.Buffer) writer := zip.NewWriter(buf)
// 添加一个包含文本的文件 file1, err := writer.Create("hello.txt") if err != nil { log.Fatal(err) } _, err = file1.Write([]byte("你好,世界!这是来自 ZIP 归档的文件。")) if err != nil { log.Fatal(err) }
// 在子文件夹中添加文件 file2, err := writer.Create("docs/readme.md") if err != nil { log.Fatal(err) } _, err = file2.Write([]byte("# 文档readme 的内容。")) if err != nil { log.Fatal(err) }
// 必须关闭 writer err = writer.Close() if err != nil { log.Fatal(err) }
// 将归档保存到文件 err = os.WriteFile("example.zip", buf.Bytes(), 0644) if err != nil { log.Fatal(err) } fmt.Println("归档已创建:example.zip")}
func main() { createZip()}从 ZIP 中读取和提取文件
要读取归档,使用 zip.OpenReader() 或 zip.NewReader()(用于内存中的数据)。每个文件由 zip.File 结构表示。
func readZip() { reader, err := zip.OpenReader("example.zip") if err != nil { log.Fatal(err) } defer reader.Close()
for _, f := range reader.File { fmt.Printf("文件:%s(大小:%d 字节)", f.Name, f.UncompressedSize64)
// 打开文件内容 rc, err := f.Open() if err != nil { log.Fatal(err) }
// 读取内容 content, err := io.ReadAll(rc) if err != nil { log.Fatal(err) } rc.Close()
fmt.Printf("内容:%s
", content) }}将所有文件提取到磁盘
通常需要将归档解压到指定目录。此时正确创建子文件夹很重要。
func extractZip(src, dest string) { reader, err := zip.OpenReader(src) if err != nil { log.Fatal(err) } defer reader.Close()
for _, f := range reader.File { // 提取路径 fpath := filepath.Join(dest, f.Name)
// 检查路径是否超出 dest 范围(安全性) if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { log.Fatalf("无效路径:%s", fpath) }
// 创建文件夹 if f.FileInfo