上周给朋友拷一包剧,字幕、nfo、海报都在,压缩完发过去,他在 Mac 上一解,中文名全成了方块和问号。文件本身没坏,就是名字没法用。我本来想随口回一句「用 7-Zip 压就不会乱码」,结果自己动手一测,发现这句话是错的——7-Zip 命令行版默认写进 zip 的东西,恰好是乱码的根源之一。
既然工具都装好了,速度就顺手一起量了,因为「该用哪个压缩工具」的另一半答案在耗时和内存上。
测的是什么
两个目录,都是真实文件,不是造的数据。
- 目录 A:本项目依赖目录,1677 个文件、177MB,其中 565 个 .js,其余是 .md、.json、.map,典型的「碎文件 + 文本」
- 目录 B:一个 258MB 的影视目录,含 256MB 已压制的码流、一份 srt、一个 1.4MB 的预告片
机器是 Ryzen 5 3550H、16GB 内存、SATA SSD、Win11。参与对比的四个工具:
- 7-Zip 25.01,用官方 Extra 包里的 7za.exe,压缩包本身只有 1.6MB
- Windows 自带的「右键 → 压缩为 ZIP」,用 Compress-Archive 复现同一个流程
- Windows 11 自带的 tar.exe,实际是 bsdtar 3.8.9
- 每项跑完记墙钟耗时,同时每 100 毫秒采一次进程内存,取峰值
速度:系统自带 40.7 秒,7-Zip 的 zip 只用 21 秒
目录 A,177MB、1677 个文件:
- 7z 固实 mx=5:72.9 秒,压完 39.13MB
- 7z 固实 mx=9:79.1 秒,37.01MB
- 7z 非固实 mx=5:66.8 秒,40.86MB
- zip mx=5、8 线程:21.1 秒,56.41MB
- zip mx=9、8 线程:131.2 秒,55.69MB
- zip mx=1、8 线程:4.58 秒,59.69MB
- zip mx=5、单线程:36.6 秒,56.41MB
- bsdtar:12.6 秒,58.16MB
- 系统自带 Optimal:40.7 秒,58.03MB
- 系统自带 Fastest:31.0 秒,64.88MB
先看最常用的那条:右键压缩。40.7 秒、58.03MB。同一批文件交给 7-Zip 的 zip 模式,21.1 秒、56.41MB——时间少一半,体积还小 1.6MB。也就是说右键压缩唯一的好处是「不用装软件」,性能上两头都不占。
再看 -mx=9。这个参数在论坛里被当成「压得更狠」的银弹,实测是纯坑:131.2 秒,比 mx=5 慢 6.2 倍,体积只从 56.41MB 降到 55.69MB,省下 0.72MB,1.3%。原因不复杂,zip 的 deflate 是每个文件独立压缩,档位只影响单个文件内部的搜索强度,跨文件一点不共享,天花板本来就在那儿。
反而 mx=1 值得一说:4.58 秒压完,59.69MB。比 mx=5 只大 3.3MB,速度是它的 4.6 倍。给朋友传、当天就删的包,用这个档最划算。
bsdtar 12.6 秒,是全场最快,比 7-Zip 的 zip 还快 1.7 倍。它默认多线程、实现也轻,但它的中文名有问题,下面单独说。
还有一组数据能说明「多线程」这件事被高估了:zip mx=5 单线程 36.6 秒,8 线程 21.1 秒,只快了 1.73 倍,不是 8 倍。zip 是按文件分块并行的,1677 个文件里大半是几百字节的小文件,线程开满也在排队等磁盘和杀毒软件扫新文件。
固化压缩省得比想象少
7z 固实 39.13MB,非固实 40.86MB,只差 1.73MB,4.2%,代价是多花 6 秒。固实压缩(把多个文件连成一条流再压)的收益主要来自「很多内容高度相似的小文件」,比如同一个模板生成的几百个 html;我这批依赖文件差异太大,长距离匹配基本用不上。
真正拉开差距的是内存:
- 7z mx=9 固实:峰值 1238MB
- 7z mx=5 固实:494MB
- 7z mx=5 非固实:387MB
- zip 8 线程:80MB
- zip 单线程:15.4MB
- bsdtar:7.1MB
- 系统自带:89MB
7z mx=9 那 1.2GB 峰值,在 16GB 的台机上无所谓,在只有 1GB、2GB 内存的软路由、老 NAS、电视盒子上就是直接把机器顶死。这也是我给小主机推荐 zip 而不是 7z 的原因,跟压缩率无关,纯粹是内存。
码流那 258MB,压完一分钱没省
目录 B,258MB,其中 256MB 是已经压过一遍的码流:
- 7z mx=5 固实:35.8 秒,257.41MB,峰值内存 1198MB
- zip mx=5:20.7 秒,257.40MB
- zip mx=1:16.0 秒,257.40MB
- bsdtar:15.1 秒,257.48MB
四个结果体积几乎一模一样,比率 1.00x。H.264、HEVC 的码流和 JPEG 一样,熵已经被榨干了,任何通用压缩算法都找不到可压的冗余,只能原样存。
但时间白花了 15 到 36 秒,7z 还额外吃了 1.2GB 内存。这就是「把整季剧打个包存起来」这件事的真相:真正被压缩的只有字幕、nfo、海报那几 MB,正片那部分你只是让 CPU 把 256MB 读一遍、写一遍。
想让 CPU 别白跑,用 store 模式(zip 的 -mx=0),几十毫秒就过完,体积一分不差。
中文名:三个工具写进去的东西完全不一样
这段是这次最值得记的。zip 的文件名没有强制编码,靠两样东西约定:通用标志位第 11 位(UTF-8 标志),和扩展字段。我把同一组中文名——「第一集 字幕.srt」「海报 终版.jpg」「说明.txt」——分别压了四遍,然后直接读 zip 的中央目录看字节:
- 7-Zip 25.01 命令行默认:名字写成 GBK 字节(b5 da d2 bb …),UTF-8 标志位是 0,主机标识写 DOS,但额外塞了一个 0x7075 Unicode Path 扩展字段,里面存的是 UTF-8 名。会读这个字段的工具(新版 7-Zip、Python 3.13)能还原,只按 UTF-8 猜名字的工具就乱。
- 7-Zip 加
-mcu=on:名字是 UTF-8 字节,标志位 1,干净利落。 - 系统自带 Compress-Archive:UTF-8 字节加标志位 1,不依赖任何扩展字段,是最规范的一档。
- Windows 自带的 tar.exe(bsdtar 3.8.9):名字是 GBK 字节、标志位 0、没有 0x7075,可主机标识偏偏写成了 Unix(3)。
最后这个组合最要命。我用 7za 去解 bsdtar 打的包,解出来的文件名是「˵.txt」这种残字——字节和声明互相矛盾,工具只能二选一,选哪个都错。看起来是 7-Zip 见主机标识是 Unix,就按 UTF-8 去读名字,而字节其实是 GBK。
对比一下就很清楚:
- 同一个 GBK 字节、带 0x7075 兜底的包,7za 解出来三个中文名全部正常
- 系统自带压缩的包,7za 解出来也正常
- bsdtar 那个包,7za 解出来名字全烂
所以「压缩包乱码」不是玄学,是三个字段有没有对齐的问题。比较稳的做法只有三条:给跨平台的人传,要么用系统自带压缩(最规范),要么 7z 加 -mcu=on,要么直接用 7z 格式——7z 容器内部强制 UTF-16 存名字,没有这段历史包袱。
我现在的用法
- 传给 Mac、Linux、手机用户:7z 格式,或者 zip 加
-mcu=on - 只在自己 Windows 上备份、自己解:zip
-mx=5,21 秒、56MB、80MB 内存,别碰-mx=9 - 小内存的软路由、老 NAS、电视盒子:用 zip,不要 7z 的高档位,1.2GB 峰值真的会顶死
- 归档整季剧:把字幕、nfo、海报单独打一包,正片原样放着,整包压只是让 CPU 白跑
- 系统自带的右键压缩:急用可以,但不值得当默认,慢且体积大
你们往 NAS 上归档片子的时候,是整包压一遍,还是像我这样只压字幕那一层?