压缩比为原始文件大小与压缩后文件大小的比值,即“压缩前字节数:压缩后字节数”,需确保两者均为未编码的原始二进制长度,不可使用base64或hex等编码格式参与计算。

压缩比计算公式必须明确原始与压缩后字节长度
压缩比不是 Go 标准库直接提供的指标,而是你自己用两个 len([]byte) 相除得出的比值。关键在于:原始数据必须是未编码的二进制切片(比如从文件读出的 []byte),压缩后也必须是原始压缩格式(如 zlib 或 gzip 输出的 []byte),不能是 Base64 编码或 hex 字符串——否则长度失真,算出来完全没意义。
常见错误是拿 JSON 字符串去压,或者把 gzip.NewReader 的输出误当作压缩数据;实际上你要的是 gzip.Write 后得到的底层 buffer 内容长度。
用 compress/gzip 压缩并获取真实压缩后长度
Go 的 compress/gzip 默认写入 io.Writer,不直接返回 []byte。要拿到压缩后字节长度,得用 bytes.Buffer 接住输出:
var buf bytes.Buffer gw := gzip.NewWriter(&buf) gw.Write(originalData) // originalData 是 []byte gw.Close() // 必须调用,否则数据可能未 flush compressedLen := buf.Len()
-
gw.Close()不可省略——它会写入 gzip 尾部校验和和长度信息,缺了会导致压缩不完整、解压失败,且buf.Len()偏小 - 别用
gw.Flush()替代Close(),它不写尾部,压缩流不合法 - 如果原始数据极小(如空切片或几个字节),gzip 可能因 header 开销反而更大,此时压缩比 > 1.0 是正常现象
不同压缩器对同一数据结果差异很大
compress/zlib、compress/flate、compress/zstd(需第三方)对同一段二进制数据产出的长度不同,直接影响压缩比数值。例如:
-
zlib默认使用 DEFLATE,header 比gzip略小,适合嵌入式或协议头紧凑场景 -
gzip多 18 字节固定 header + trailer,但兼容性最好 -
zstd在中高阶压缩级别下通常比 gzip 小 10–20%,但 Go 官方不内置,需引入github.com/klauspost/compress/zstd - 压缩级别设置(如
gzip.BestSpeedvsgzip.BestCompression)会显著影响buf.Len(),务必在业务场景中固定级别再比对
注意内存分配与边界情况
计算压缩比本身很快,但实际压缩过程会分配新内存。如果你反复计算大量小数据块的压缩比(比如日志采样),要注意:
- 避免每次新建
bytes.Buffer——可复用并调用buf.Reset() - 原始数据为
nil时,len(nil)是 0,但gzip.Write(nil)不 panic,压缩后长度仍为合法值(约 20 字节),需按需处理零长输入逻辑 - 若原始数据含大量重复零字节,某些压缩器(如
flate)可能触发特殊优化,而随机加密数据则几乎无法压缩——压缩比接近 1.0 是预期行为,不是 bug
真正容易被忽略的是:你拿去压缩的“原始数据”是否已带某种编码或冗余结构。比如 protobuf 序列化后的二进制本身已有一定压缩倾向,而 base64 编码后再压只会更差——确认输入形态,比选哪个库更重要。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











