压缩比需手动计算:读取原始文件大小,用bytes.buffer接收压缩输出并close()后取len(),再算float64(origsize)/float64(compressedsize),注意算法、级别、单位统一及空文件校验。

压缩比计算的核心公式必须手动实现
Go 标准库不提供现成的「压缩比」函数,compress/gzip、compress/zlib 等包只负责压缩/解压,不返回原始与压缩后字节长度的比值。你需要自己读取原始文件、调用压缩、获取两者 len(),再做除法。
关键点在于:压缩结果必须是完整写入内存或临时 buffer 的字节流,不能直接用 io.Copy 流式丢弃数据——否则拿不到压缩后大小。
- 错误做法:
gzip.NewWriter(os.Stdout)→ 输出到终端,无法获取长度 - 正确做法:
gzip.NewWriter(&buf),其中buf是bytes.Buffer - 注意:压缩器必须显式
Close(),否则内部缓冲未 flush,buf.Len()会偏小
读取大文件时避免内存爆炸
如果直接用 os.ReadFile() 加载几个 GB 的文件,程序会 OOM。实际脚本应分两步处理:先用 os.Stat() 获取原始大小,再用流式压缩(io.Pipe 或分块 io.Copy)避免全量加载。
但注意:流式压缩无法提前知道压缩后大小,除非你把整个压缩输出也写进 bytes.Buffer —— 这又回到内存问题。权衡之下,对 >100MB 的文件,建议改用命令行调用系统工具并解析输出:
-
gzip -c file.txt | wc -c得压缩后字节数 -
wc -c file.txt得原始字节数 - 用
exec.Command执行并捕获 stdout,比纯 Go 实现更省内存且兼容性好
gzip 与 zstd 压缩比差异显著,选错算法会误导结论
用 compress/gzip 算出的压缩比,和用 github.com/klauspost/compress/zstd 算出的完全不可比。不同算法默认压缩级别、字典、窗口大小都不同。
例如:同一份 JSON 文件,gzip 默认级别(-1)可能得 3.2x,zstd 默认(ZSTD_DEFAULT_CLEVEL)可能达 4.7x。如果你脚本只支持 gzip,却拿它和别人标称的「zstd 压缩比」对比,结果毫无意义。
- 务必在输出中明确标注算法和级别,如
gzip-6或zstd-3 - 设置压缩级别用
gzip.NewWriterLevel(&buf, level),level范围是gzip.NoCompression到gzip.BestCompression - Zstandard 需额外引入第三方包,且其
EncoderOptions影响更大,不能简单套用 gzip 接口
浮点精度与单位混淆是常见误差源
压缩比通常表示为「原始大小 / 压缩后大小」,结果大于 1;但有人误算成「压缩后 / 原始」,得出 0.3 之类的小数,还叫它「压缩率」——术语混乱会导致协作出错。
另一个坑是单位:os.Stat().Size() 返回字节数,但用户常以为是 KB 或 MB。若脚本输出「压缩比:3.2」,必须确认分母分子单位一致,且不混用十进制(1KB=1000B)和二进制(1KiB=1024B)。
- 推荐统一用字节计算,最终结果保留两位小数:
float64(origSize) / float64(compressedSize) - 避免用
fmt.Printf("%.2f", ratio)直接输出——当 ratio 是inf(压缩后为 0)或nan(除零)时会崩溃,需提前检查compressedSize > 0 - 如果原始文件为空(0 字节),压缩后也是 0 字节,此时压缩比无定义,应单独提示而非硬算
真正难的不是写几行 gzip.NewWriter,而是确保每次比较都在相同前提下:同文件、同算法、同级别、同单位、同空文件处理逻辑。少一个条件,数字就失去参照价值。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











