Golang高效合并(拼接)多个gzip压缩文件

有时我们可能会遇到需要把多个 gzip 文件合并成单个 gzip 文件的场景,最简单最容易的方式是把每个gzip文件都先解压,然后合并成一个文件后再次进行压缩,最终得到我们想要的结果,但这种先解压后压缩的方式显然效率不高,有没有更好的实现方式呢,答案是肯定的,Linux下常用的压缩库 Zlib 的两位主要作者之一 Mark Adler 就给我们提供了一个这样的示例程序:

https://github.com/madler/zlib/blob/develop/examples/gzjoin.c

从说明中我们可以看出,这种方式只需要解压一遍所有文件(用于找到特定的比特位并修改它),但不需要做任何额外的压缩操作,而且合并后的 gzip 文件末尾的 crc32 校验和也不需要从头计算(根据源 gzip 文件的校验和用函数 crc32_combine 便可计算出),一般来说,deflate 解压操作要比压缩操作速度快很多,所以这种合并 gzip 文件的方式在性能上是相当高效的,如果是在 C 语言中实现,我们就可以直接"借鉴" Mark Adler 大佬的代码。

针对同一个数据源,用 Go 内置 compress/gzip 包,压缩和解压缩简单的性能对比:

bash 复制代码
goos: darwin
goarch: arm64
pkg: go-redis-demo
BenchmarkGzip
    goredis_test.go:60: test input data length: 778785
BenchmarkGzip/compress
BenchmarkGzip/compress-8         	     115	   9727792 ns/op
BenchmarkGzip/decompress
BenchmarkGzip/decompress-8       	     609	   1957044 ns/op

使用默认压缩级别,解压速度是压缩速度的5倍,使用 Linux 下的命令行压缩工具 gzip 对比结果也差不多:

命令行工具 gzip 压缩速度:

bash 复制代码
$ ll test.html 
-rw-r--r--  1 zy  staff  778785 Jul 30 14:28 test.html
$ 
$ time gzip -kf test.html

real    0m0.034s
user    0m0.024s
sys     0m0.007s
$ time gzip -kf test.html

real    0m0.032s
user    0m0.025s
sys     0m0.004s
$ time gzip -kf test.html

real    0m0.030s
user    0m0.025s
sys     0m0.004s

命令行工具 gzip 解压缩速度:

bash 复制代码
$ ll
total 1808
-rw-r--r--  1 zy  staff  778785 Jul 30 14:28 test.html
-rw-r--r--  1 zy  staff  142127 Jul 30 14:28 test.html.gz
$ 
$ time gzip -dkf test.html.gz

real    0m0.013s
user    0m0.003s
sys     0m0.005s
$ time gzip -dkf test.html.gz

real    0m0.008s
user    0m0.003s
sys     0m0.004s
$ time gzip -dkf test.html.gz

real    0m0.010s
user    0m0.003s
sys     0m0.004s

解压也是比压缩快 3-4 倍左右,这就意味着在合并 gzip 文件时省去压缩操作会对性能产生极大提升。

Go 语言实现

用 Go 内置的 compress/gzip 或者 compress/flate 包无法实现与 gzjoin.c 相同的功能,因为 gzjoin.c 的实现依赖解压时的 Z_BLOCK 刷写模式,而 compress/flate 解压缩时并不支持指定 Flush 模式,所以我们只能换一种思路,利用 cgo 来直接调用 Zlib C 库,具体实现可以参考我这里的代码 https://github.com/zhyee/deflatejoin,如果对实现细节不感兴趣,也可以在你的Go项目中直接调用该module, 与用 解压 --> 合并文件 --> 再压缩 的方式性能对比差不多提升了10倍以上:

bash 复制代码
goos: darwin
goarch: arm64
pkg: github.com/zhyee/deflatejoin
BenchmarkConcatGzip/concat-standard-go-8                       9         123559972 ns/op         1257826 B/op       1261 allocs/op
BenchmarkConcatGzip/concat-deflatejoin-8                     100          10784015 ns/op           30289 B/op         41 allocs/op
相关推荐
DemonAvenger5 小时前
深入剖析 sync.Once:实现原理、应用场景与实战经验
分布式·架构·go
一个热爱生活的普通人1 天前
Go语言中 Mutex 的实现原理
后端·go
孔令飞1 天前
关于 LLMOPS 的一些粗浅思考
人工智能·云原生·go
小戴同学1 天前
实时系统降低延时的利器
后端·性能优化·go
Golang菜鸟2 天前
golang中的组合多态
后端·go
Serverless社区2 天前
函数计算支持热门 MCP Server 一键部署
go
Wo3Shi4七2 天前
二叉树数组表示
数据结构·后端·go
网络研究院2 天前
您需要了解的有关 Go、Rust 和 Zig 的信息
开发语言·rust·go·功能·发展·zig
27669582922 天前
拼多多 anti-token unidbg 分析
java·python·go·拼多多·pdd·pxx·anti-token
程序员爱钓鱼3 天前
Go 语言邮件发送完全指南:轻松实现邮件通知功能
后端·go·排序算法