go 的 compress/gzip 不提供压缩比接口,需手动计算原始与压缩后字节长度;压缩级别用预设常量(如 gzip.bestspeed=1、defaultcompression=-1、bestcompression=9),非百分比;必须调用 close() 才能获取准确压缩比。

Go 的 compress/gzip 不提供直接的“压缩比”计算接口,必须手动对比原始与压缩后字节长度;压缩级别通过 SetLevel 控制,但数值含义和实际效果容易误判。
gzip.Writer.SetLevel() 参数值不是百分比,而是预设常量
传给 SetLevel 的整数不是 0–100 的压缩率百分比,而是 Go 标准库定义的几个固定常量:
-
gzip.BestSpeed(值为1):最快,压缩比最低 -
gzip.DefaultCompression(值为-1):默认平衡点,推荐多数场景使用 -
gzip.BestCompression(值为9):最慢,压缩比最高
传入其他整数(如 5 或 7)虽能工作,但属于未公开行为,不同 Go 版本可能表现不一致。别硬凑中间值,用常量更稳。
压缩比必须自己算,gzip.Writer 不返回原始/压缩大小
压缩过程是流式写入,gzip.Writer 本身不记录原始数据长度,也不暴露压缩后实时大小。要得到压缩比,得在外部做两件事:
- 先用
len([]byte(data))得到原始字节数 - 压缩完成后调用
buf.Len()(假设你用bytes.Buffer作底层写入器) - 压缩比 = 原始字节数 ÷ 压缩后字节数(注意:结果 > 1 才说明有压缩收益)
示例关键片段:
buf := &bytes.Buffer{}
gz := gzip.NewWriter(buf)
gz.Write([]byte("your data here"))
gz.Close() // 必须调用,否则 buf.Len() 可能偏小
original := len([]byte("your data here"))
compressed := buf.Len()
ratio := float64(original) / float64(compressed)
设置压缩级别后,实际压缩比受内容影响极大
同一级别对不同数据效果差异明显:
- 纯文本、日志、JSON 等重复模式多的数据,
gzip.BestCompression能达到 3:1 甚至更高 - 已压缩过的数据(如 JPEG、MP4、ZIP),再套一层 gzip 几乎不减体积,还可能略微增大(因 gzip header 开销)
- 随机二进制或加密数据基本无法压缩,无论设什么级别,
ratio都接近 1.0
所以不要只看级别数字,务必用真实业务数据实测。尤其在 HTTP 响应压缩中,若后端返回的是 base64 编码图片,开 gzip 反而浪费 CPU。
别忽略 Close() —— 不调用它,压缩比计算就失效
gzip.Writer.Close() 不只是“收尾”,它会强制刷新所有缓冲区、写入 gzip trailer(CRC32 和 ISIZE 字段)。没调用时:
-
buf.Len()返回的只是部分压缩数据,长度不准 - 生成的字节流无法被标准解压工具识别(报
invalid checksum或unexpected EOF) - 压缩比计算结果虚高,误导判断
即使你用 Flush(),也不能替代 Close() —— 后者才是完整封包动作。
压缩比是个观测值,不是配置项;级别是离散档位,不是滑动条。真正影响结果的,是你喂给 gzip.Writer 的数据本身是否可压缩,以及你有没有让压缩流程完整走完。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











