压缩率需用单文件zip中compressedsize64除以uncompressedsize64,而非zip总大小除以原始大小;多文件zip因目录项等开销,总大小必大于各compressedsize64之和。

用 archive/zip 读取原始与压缩后字节长度
Go 没有内置“压缩率计算函数”,必须手动比对源文件和 ZIP 包内对应文件的大小。关键不是解压,而是从 ZIP 中读取 FileHeader.UncompressedSize64 和 ZIP 文件自身总大小(或目标文件在 ZIP 中的 CompressedSize64)。注意:CompressedSize64 是 ZIP 流中该文件实际占用字节数(含 ZIP 头、校验等开销),不是整个 ZIP 文件大小。
常见错误是直接用 os.Stat("archive.zip").Size() 除以所有文件原始大小之和——这忽略了 ZIP 中多个文件、目录项、中央目录、额外字段等带来的非线性开销,结果偏差大。
- 只统计目标文件(非整个 ZIP)时,用
zip.File.FileInfo().Size()得原始大小,zip.File.CompressedSize64得其在 ZIP 中压缩后尺寸 - ZIP 文件总大小 ≠ 所有
CompressedSize64之和;多文件 ZIP 的总大小一定大于各文件压缩尺寸之和 - 若 ZIP 含加密或非标准压缩方法(如 ZSTD),
CompressedSize64仍有效,但无法直接反推算法效率
单文件 ZIP 压缩率计算示例(无密码、Store/Deflate)
适用于你控制打包过程、且 ZIP 内仅一个文件的场景(例如生成固件包、单资源归档)。此时 ZIP 总大小 ≈ 文件压缩尺寸 + 极小固定头开销(通常 CompressedSize64。
src, _ := os.ReadFile("data.bin")
zipPath := "data.bin.zip"
zipFile, _ := os.Open(zipPath)
defer zipFile.Close()
<p>zr, _ := zip.NewReader(zipFile, zipFile.Stat().Size())
if len(zr.File) != 1 {
log.Fatal("expect exactly one file in zip")
}
f := zr.File[0]
ratio := float64(f.CompressedSize64) / float64(len(src))
fmt.Printf("Compression ratio: %.3f (smaller is better)\n", ratio)
</p>
注意:f.CompressedSize64 在 Store(无压缩)模式下等于原始大小;Deflate 下通常显著更小。若 ZIP 是用 zip -0(store)或 -9(max deflate)生成的,这个 ratio 能反映实际压缩效果。
为什么不能依赖 zip.File.UncompressedSize64 做分母?
它看起来是“原始大小”,但实际可能不准:某些 ZIP 工具写入 32 位 size 字段后未补全 64 位字段,导致 UncompressedSize64 为 0 或截断值;Go 的 archive/zip 在读取时若检测到 size 缺失,会尝试从 local header 解析,但不保证 100% 成功。
- 更可靠的方式:用
os.Stat("original.file").Size()作为原始大小(前提是你知道原始路径) - 如果原始文件已删除或不可访问,且 ZIP 中只有单文件,可用
f.FileInfo().Size()—— 它内部优先使用UncompressedSize64,失败时 fallback 到 local header 解析,比直接读UncompressedSize64更健壮 - 对跨平台 ZIP(Windows 打包、Linux 解析),文件名编码、权限位等也会影响 header 解析稳定性,别假设
UncompressedSize64总是可用
多文件 ZIP 的“整体压缩率”怎么算才合理?
没有唯一正确答案,取决于你要回答的问题。如果是“用户传一个 ZIP,想知道它比原始文件夹节省多少空间”,就该用:(原始文件夹总大小 - ZIP 文件总大小) / 原始文件夹总大小。
实操时需注意:
- 原始文件夹总大小 = 递归
os.WalkDir所有常规文件的FileInfo.Size()之和(跳过 symlink、dir、device node) - ZIP 文件总大小 =
os.Stat("archive.zip").Size(),不是 ZIP 内各CompressedSize64相加 - 若 ZIP 含空目录、符号链接、扩展属性(xattrs),它们不占
CompressedSize64但增加 ZIP 总体积,这种差异会被自然计入结果 - 别用
zip.File.Header.Size或zip.File.Header.Extra手动累加——header 结构复杂,且 Go 不暴露完整解析接口
压缩率数字本身意义有限,真正重要的是:你是否在相同输入、相同 ZIP 参数(-0 到 -9、算法)、相同 Go 版本下做横向对比。跨工具(7z vs zip cli vs Go stdlib)的结果不可直接比较。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











