Go 语言实现 ZIP 文件与目录压缩完整示例
本文演示如何利用 Go 标准库中的 archive/zip、io/ioutil 和 filepath 等模块,编写一个支持单文件或整个目录递归打包为 ZIP 文件的工具函数。核心逻辑涉及使用内存缓冲流优化写入性能,以及正确设置 ZipFileHeader 以确保归档格式符合规范。
实现原理与准备条件
要实现 ZIP 压缩功能,无需引入第三方依赖。Go 语言标准库已提供完整的底层支持。我们需要关注的核心组件包括:
- 输入源:可以是单个文件路径,也可以是根目录路径。
- 内存缓冲
bytes.Buffer:用于暂存压缩数据,避免直接逐块写入磁盘文件带来的 I/O 开销。 - 压缩器
zip.NewWriter:负责将缓冲包装为 ZIP 写入流。 - 遍历机制
filepath.Walk:递归遍历目标目录下的所有子文件和子目录。
第1步:定义主入口与压缩函数调用
在 main 函数中初始化测试数据。我们传入源路径和目标输出文件名,并检查执行过程中是否发生错误。注意,示例中的目标文件名不包含后缀,实际应用中建议由程序自动添加或用户自行指定。
package main
import (
"fmt"
)
第2步:构建带缓冲的 ZIP Writer
创建固定大小的字节缓冲区(例如 10MB)以减少内存重新分配的次数。使用 zip.NewWriter(buf) 创建一个关联该缓冲区的 Zip 写入器对象。
buf := bytes.NewBuffer(make([]byte, 0, 10*1024*1024))
myzip := zip.NewWriter(buf)
第3步:递归遍历并处理文件头信息
使用 filepath.Walk 方法遍历输入路径。对于每一个访问到的文件或目录,需获取其 os.FileInfo 并通过 zip.FileInfoHeader(info) 生成初始的文件头结构。
关键点在于修正 header.Name。必须通过 filepath.Rel(filepath.Dir(frm), path) 计算相对路径,确保解压后的目录结构与预期一致,而非写入绝对路径。
若非目录,则强制指定 header.Method = 8(即 deflate 压缩算法)以启用数据压缩;若是目录,数据部分留空。
第4步:写入数据并关闭资源
通过 myzip.CreateHeader(header) 获得具体的 io.Writer 接口。若当前项为非空目录文件,读取其全部内容(ioutil.ReadFile)并写入该接口。遍历完成后,必须先调用 myzip.Close() 释放压缩器资源,这将把内存缓冲区中的数据整理完毕。最后,创建目标文件并将缓冲区的內容一次性拷贝至磁盘文件中。
完整源码解析
以下是可直接运行的完整 Go 代码。该程序演示了从初始化缓冲、遍历目录到最终落盘的全过程。
package main
import (
"archive/zip"
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
)
func main() {
if err := compress(`gopkg`, `gopkg.zip`); err != nil {
fmt.Println(err)
}
}
// 参数frm可以是文件或目录,不会给dst添加.zip扩展名
func compress(frm, dst string) error {
buf := bytes.NewBuffer(make([]byte, 0, 10*1024*1024)) // 创建一个读写缓冲
myzip := zip.NewWriter(buf) // 用压缩器包装该缓冲
// 用Walk方法来将所有目录下的文件写入zip
err := filepath.Walk(frm, func(path string, info os.FileInfo, err error) error {
var file []byte
if err != nil {
return filepath.SkipDir
}
header, err := zip.FileInfoHeader(info) // 转换为zip格式的文件信息
if err != nil {
return filepath.SkipDir
}
header.Name, _ = filepath.Rel(filepath.Dir(frm), path)
if !info.IsDir() {
// 确定采用的压缩算法(这个是内建注册的deflate)
header.Method = 8
file, err = ioutil.ReadFile(path) // 获取文件内容
if err != nil {
return filepath.SkipDir
}
} else {
file = nil
}
// 上面的部分如果出错都返回filepath.SkipDir
// 下面的部分如果出错都直接返回该错误
// 目的是尽可能的压缩目录下的文件,同时保证zip文件格式正确
w, err := myzip.CreateHeader(header) // 创建一条记录并写入文件信息
if err != nil {
return err
}
_, err = w.Write(file) // 非目录文件会写入数据,目录不会写入数据
if err != nil { // 因为目录的内容可能会修改
return err // 最关键的是我不知道咋获得目录文件的内容
}
return nil
})
if err != nil {
return err
}
myzip.Close() // 关闭压缩器,让压缩器缓冲中的数据写入buf
file, err := os.Create(dst) // 建立zip文件
if err != nil {
return err
}
defer file.Close()
_, err = buf.WriteTo(file) // 将buf中的数据写入文件
if err != nil {
return err
}
return nil
}
运行结果判断
成功执行后,会在当前工作目录下生成指定的 .zip 归档文件。可以通过解压该软件验证内部的文件层级是否与原始目录结构完全吻合。若控制台无报错输出,即表示操作顺利完成。
以上就是 Go 语言制作 ZIP 压缩程序的详细内容,更多关于 Golang 开发基础资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









