最直接方式是用os.Stat分别获取原始文件和压缩后文件的Size(),计算压缩率=compressed.Size()/original.Size();注意ZIP需用file.Open读取真实压缩字节而非依赖CompressedSize64,gzip需考虑header开销,且压缩效果受算法级别和文件类型显著影响。

用 os.Stat 比较原始与压缩后文件大小最直接
检测压缩效果,本质是看「压缩率」,也就是原始文件体积和压缩后体积的比值。Go 里没有内置“压缩效果评估”函数,但 os.Stat 足够可靠:它返回 os.FileInfo,其中 Size() 方法给出字节数,不依赖内容解析,快且稳定。
常见错误是试图读取压缩包内部文件头来估算——这既慢又不准(比如 ZIP 可能含未压缩项、加密项或冗余元数据)。真实效果只看最终写盘体积。
- 先调用
os.Stat("input.txt")获取原始大小 - 再调用
os.Stat("input.txt.zip")获取压缩后大小 - 压缩率 =
float64(compressed.Size()) / float64(original.Size()),越接近 0 效果越好(但注意:空文件或极小文件可能导致除零或失真) - 若压缩后反而更大(比率 > 1.0),说明该文件不适合当前压缩算法(如已加密、高熵、或本身是 JPEG/PNG 等已有压缩格式)
用 archive/zip 读取实际压缩字节而非声明大小
zip.File 的 UncompressedSize64 和 CompressedSize64 字段看起来能直接算压缩率,但要注意:它们来自 ZIP 中央目录,可能被篡改或不准确;更关键的是,ZIP 支持 STORE(无压缩)和 DEFLATE 等多种方式混存,单个 ZIP 包内各文件压缩率不同。
所以,如果你关心的是「某个具体文件在 ZIP 中的实际压缩表现」,得打开 ZIP、定位到对应 *zip.File,然后读取其压缩数据流并统计真实长度:
立即学习“go语言免费学习笔记(深入)”;
rc, err := file.Open()
if err != nil {
return 0, err
}
defer rc.Close()
// 注意:这里读取的是压缩后的原始字节,不是解压后内容
compressedData, err := io.ReadAll(rc)
if err != nil {
return 0, err
}
return int64(len(compressedData)), nil
这个值才真正反映该文件在 ZIP 中占用的磁盘空间,比 CompressedSize64 更可信(尤其对非标准 ZIP 工具生成的包)。
gzip 压缩效果检测要绕开 gzip.Header 的干扰
Go 的 compress/gzip 默认写入标准 gzip header(含 OS 标识、修改时间等),这部分固定约 10–20 字节,对小文件影响显著。如果你对比的是「原始字节流」vs「gzip.Writer 写出的完整 .gz 文件」,那 header 就是有效压缩输出的一部分,应计入大小。
但若你只想评估纯 DEFLATE 流的压缩能力(比如对接嵌入式协议),就得跳过 header:
- 用
flate.NewWriter替代gzip.NewWriter,得到裸 DEFLATE 流 - gzip 文件头可被
gzip.NewReader自动识别,但flate.NewReader不处理 header,所以不能直接拿 .gz 文件喂给它 - 想测 header 开销?分别用
gzip.NewWriter和flate.NewWriter压同一段数据,再手动补上 gzip header(gzip.Header结构体字段可查文档),但通常没必要——实际部署中 header 是必须的
别忽略压缩级别和输入特征对结果的影响
同一文件用 gzip.NewWriterLevel(fw, gzip.BestCompression) 和 gzip.NoCompression 压出来大小可能差 5–10 倍。但「效果好」不等于「适合」:高阶压缩耗 CPU 多、内存大、延迟高。
真正影响压缩效果的,常是输入本身:
- 纯文本、日志、JSON/YAML:DEFLATE 类算法通常有 60–90% 压缩率
- JPEG、MP4、ZIP、PDF:基本压不动,甚至略涨(因 header 开销)
- 加密数据或随机字节:压缩率 ≈ 1.0,此时压缩纯属浪费 I/O 和 CPU
- 小文件(
所以检测效果前,先确认你压的是什么——否则数值再漂亮也没意义。


















