计算 gzip 压缩比需用 float64(len(original)) / float64(buf.len()),且必须调用 gw.close() 后取 buf.len();漏掉 close() 会导致长度偏小、压缩比虚高;.len() 比 .bytes() 更高效清晰。

用 compress/gzip 计算 gzip 压缩比时,必须读取原始和压缩后字节长度
Go 标准库不提供直接的“压缩比”函数,得自己算:float64(len(original)) / float64(len(compressed))。关键点是:不能只调用 gzip.NewWriter 后就关闭——那样会触发内部 flush,但你拿不到底层 buffer 的真实长度。正确做法是把压缩结果写入 bytes.Buffer,再取其 .Len():
var buf bytes.Buffer gw := gzip.NewWriter(&buf) gw.Write(data) gw.Close() // 必须调用,否则数据未完全写出 ratio := float64(len(data)) / float64(buf.Len())
- 漏掉
gw.Close()会导致buf.Len()偏小(仅写入部分数据),压缩比虚高 - 别用
buf.String()或buf.Bytes()再取长度——.Len()更高效且语义清晰 - gzip 默认压缩级别是
gzip.DefaultCompression,如需对比不同级别,用gzip.NewWriterLevel(&buf, level),level范围是-2(Huffman only)到9
计算 compress/zlib 和 compress/bzip2 压缩比要注意 Writer 初始化差异
zlib 和 bzip2 的 writer 行为与 gzip 不同:zlib 的 zlib.NewWriter 不需要显式 close 才完成写入(但 close 仍推荐),而 gobuffalo/buffalo-plugins/bzip2 不在标准库中,实际要用 github.com/dsnet/compress/bzip2 或 github.com/ulikunitz/xz 等第三方包;标准库只有 compress/bzip2 的解压支持,无压缩。
- zlib 示例中,
zw.Write()后可直接用buf.Len(),但调用zw.Close()能确保尾部校验和写入,影响极小但严谨起见建议保留 - bzip2 若使用
dsnet/compress/bzip2,其bzip2.NewWriter必须Close(),否则输出不完整;该包默认不启用 block sorting,压缩比低于标准 bzip2 工具 - 所有压缩器对空输入或极短数据(如
跨格式统一计算压缩比时,避免混用 io.Copy 和手动 Write
有人用 io.Copy(gw, reader) 处理大文件流,再从 bytes.Buffer 取长——这没问题;但若中间穿插了 gw.Write() 和 io.Copy() 混用,可能因 writer 内部 buffer 状态不一致导致长度不准。
- 保持操作一致:全用
Write+Close,或全用io.Copy+Close - 对大文件别全加载进内存再算——改用
os.Stat获取源文件大小,压缩时边写边计数(io.MultiWriter包裹hash.Hash或自定义io.Writer统计写入量) - 注意:不同压缩器对同一数据的压缩比差异主要来自算法设计(LZ77 vs BWT)、字典大小、是否支持多段编码,而非 Go 实现本身;标准库实现已足够可靠
实测发现 compress/snappy 压缩比常低于 gzip,但耗时少一个数量级
snappy 不追求高压缩率,目标是速度。它的压缩比计算方式一样,但典型值在 1.2–2.5×,远低于 gzip 的 3–10×(取决于数据)。使用前需确认是否引入了 github.com/golang/snappy(非标准库):
import "github.com/golang/snappy" // ... compressed := snappy.Encode(nil, data) ratio := float64(len(data)) / float64(len(compressed))
-
snappy.Encode是无状态函数,无需 Writer,也无级别参数——这意味着无法调优压缩比,只能接受固定行为 - 它不保证压缩后一定更小;对随机数据或已压缩数据(如 JPEG),输出可能膨胀 10%~20%
- 如果业务场景是 RPC payload 或日志传输,且 CPU 敏感,snappy 常比 gzip 更合适——压缩比低一点,但序列化总延迟下降明显
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











