Go标准库不提供压缩比函数,需手动统计原始与压缩后字节数再相除;gzip必须复用Writer并调用Close()确保尾部写入,zip需区分单文件与归档整体压缩比,跨格式对比须固定参数和测量方式。

压缩比计算的核心公式必须手动实现
Go 标准库不提供直接返回「压缩比」的函数,compress/flate、compress/gzip、archive/zip 等包只负责压缩/解压,不记录原始大小与压缩后大小的比值。你得自己读取源文件、写入压缩结果、再用两个 os.Stat 的 Size() 相除。
gzip 压缩比计算要小心 ioutil.ReadAll 的内存陷阱
常见错误是用 ioutil.ReadAll(或 io.ReadAll)把整个压缩流读进内存再算长度——对大文件(比如 500MB 日志)会 OOM。正确做法是边压缩边计数:
- 用
gzip.NewWriter包裹一个自定义io.Writer,在Write方法里累加字节数 - 不要调用
Close()前就读取 buffer,否则 gzip 尾部校验头没写入,长度不准 - 原始文件大小用
os.Stat("input.txt").Size(),不是len(data)(后者可能因换行符处理失真)
type CountWriter struct{ N int64 }
func (w *CountWriter) Write(p []byte) (int, error) {
w.N += int64(len(p))
return len(p), nil
}
// ...
f, _ := os.Open("data.json")
defer f.Close()
gzw := gzip.NewWriter(&CountWriter{})
io.Copy(gzw, f)
gzw.Close() // 必须调用,否则尾部未写入
ratio := float64(origSize) / float64(countWriter.N)
zip 多文件压缩比需区分「单文件」和「归档整体」
zip 是容器格式,压缩比有两种理解方式,容易混淆:
- 「单文件压缩比」:对每个文件单独用 deflate 压缩,再求平均 —— 需用
zip.FileHeader.CompressedSize64和UncompressedSize64 - 「归档整体压缩比」:整个
.zip文件体积 ÷ 所有原始文件大小之和 —— 更常用,但要注意 zip 中的目录项、注释、扩展属性也占空间 - 用
archive/zip创建时默认不启用压缩(FileHeader.Method = zip.Store),务必设为zip.Deflate
不同格式间不可直接比压缩比数值
gzip、zstd、lz4 的压缩比数字看起来可比,实际不能跨算法横向对比,因为:
立即学习“go语言免费学习笔记(深入)”;
- gzip 默认只压缩一次,而 zstd 可设
WithEncoderLevel(zstd.SpeedBestCompression),级别不同结果差 30%+ - zip 的压缩发生在文件粒度,若打包 1000 个 1KB 小文件,zip 的元数据开销可能让整体压缩比反不如单个 gzip
- 某些格式(如
compress/zlib)头部比 gzip 少 2 字节,对极小文件影响显著
真正需要对比时,固定输入文件、固定压缩参数、固定测量方式(推荐用归档整体大小 ÷ 原始总大小),否则数字只是参考。


















