ouch 0.8.3 是一个压缩解压命令行工具,ouch.exe 6407680 字节,压缩包 2684389 字节,一条命令能处理 14 种归档格式。

它要解决的是:.tar.gz 用 tar 加 gzip 两条命令,.7z 要装 7-Zip,.zst 要另找一个工具,rar 又是另一套。同一个目录换个格式压,就得记住三套参数。

这次拿 10000 个文件、20857118 字节的目录树压了三遍:同一份数据打成 tar.gz、打成 zip,再和 7-Zip 打同一个 zip 做对照,最后量了把 10000 个文件解回磁盘要多久。

一个 exe 管 14 种格式

整个工具就是一个 6407680 字节的 exe,解压出来只有它和文档。帮助输出 1335 字节,第一行就把支持的格式全列了。

项值说明
压缩包2684389 字节ouch-x86_64-pc-windows-msvc
ouch.exe6407680 字节单文件,无依赖
版本0.8.3ouch --version 输出一行
--help 输出1335 字节命令与选项全在里面
支持格式14 种tar zip gz 7z xz lzma lzip bz2 bz3 lz4 sz zst rar br
测试源目录10000 个文件共 20857118 字节,平均每个 2086 字节

扩展名就是参数

不需要指定格式,输出文件名写成 o.tar.gz 就打 tar.gz,写成 o.zip 就打 zip。格式从扩展名推断,这是它和 7-Zip 最大的用法差别。

三个子命令

compress、decompress、list 各一个,别名是 c、d、l。list 不展开文件就能看归档内容,查一个几百 MB 的包里有几层目录时用它。

10000 个文件打成两种格式

源目录 10000 个文件、共 20857118 字节。打 tar.gz 用了 8.07 秒输出 266505 字节,打 zip 用了 6.47 秒输出 2052262 字节。

输出耗时体积压缩到原来的
o.tar.gz8.07 秒266505 字节1.3%
o.zip6.47 秒2052262 字节9.8%
两者体积差1.6 秒1785757 字节7.7 倍
ouch 0.8.3 在 cmd 里把同一个 10 文件目录打成 tar.gz 与 zip,dir 显示两个包的体积,随后 ouch list 直接列出归档内的目录与文件

tar.gz 比 zip 小 7.7 倍

同样是 10000 个文件,tar.gz 输出 266505 字节,zip 输出 2052262 字节,差 7.7 倍。原因不在 gzip 算法,而在于 tar 先把所有文件合并成一个流再压缩,跨文件的重复内容能被压掉。

慢 1.6 秒换来 1.8 MB

tar.gz 比 zip 多花 1.6 秒,省下 1785757 字节。要传输或长期存档选 tar.gz,要给别人双击就能解开的选 zip。

和 7-Zip 打同一个 zip

同一份数据、同样是 zip 格式,7-Zip 用 -tzip -mx=6 打出 2046231 字节,耗时 2.41 秒。

工具耗时体积
ouch → zip6.47 秒2052262 字节
7-Zip → zip2.41 秒2046231 字节
差距慢 2.7 倍多 6031 字节,0.3%

体积几乎一样,速度差 2.7 倍

两个输出的体积只差 6031 字节,0.3% 的差距可以忽略。但 2.41 秒和 6.47 秒差 2.7 倍,说明 ouch 在 zip 这条路径上没有为速度做优化。

它的优势在格式数量不在吞吐

7-Zip 打 zst 或 br 要装插件,ouch 直接吃。日常压 tar.gz 或 zip,7-Zip 更快;要处理一堆不同扩展名,ouch 省下的是记参数的时间。

解压 10000 个文件要 12.86 秒

把 tar.gz 解回磁盘用了 12.86 秒,比压缩的 8.07 秒还慢,因为瓶颈变成了创建 10000 个文件。

动作耗时
压缩到 tar.gz8.07 秒
解压 tar.gz12.86 秒
解压时要创建的文件10000 个
创建与写入次数10000 次
每个文件平均2086 字节

解压慢在文件系统不在 CPU

10000 个文件意味着 10000 次创建和写入,每写一次都有元数据开销。压缩时 CPU 是瓶颈,解压时磁盘和文件系统是瓶颈,所以解压反而更久。

小文件多的时候尤其明显

这 10000 个文件平均每个 2086 字节,都是小文件。换成几十个大文件,解压时间会明显缩短,因为总数据量没变但创建次数少了两个数量级。

list 一次列出 10422 行

不展开文件就能看包里的结构。对那个 266505 字节的 tar.gz 跑一次 list,输出 10422 行:1 行标题、421 个目录、10000 个文件。

> ouch list o.tar.gz
Archive: "o.tar.gz"
tree/
tree/mod000/
tree/mod000/sub000/
tree/mod000/sub000/file_000_00.txt
项数量
list 输出总行数10422 行
目录421 个
文件10000 个
归档自身体积266505 字节
目录层级分布根 1 个、中间 20 个、叶子 400 个

421 个目录是三层结构

根目录 1 个、中间层 20 个、叶子层 400 个,加起来 421。目录自身不占数据体积,但会让 list 的输出多出 421 行。

看结构比看内容有用

拿到一个陌生归档时,先 list 前 10 行就能判断是不是「解压出来一堆散文件」。这一步不用写磁盘,几秒出结果。

10 个文件的小目录差 5.4 倍

换成只有 10 个文本文件的小目录,同样两种格式对比:tar.gz 输出 324 字节,zip 输出 1742 字节,差 5.4 倍。

输出体积说明
d.tar.gz324 字节先合并成流再压缩
d.zip1742 字节每个文件单独压缩,各自带头部
两者差5.4 倍1742 除以 324

文件越少,头部开销占比越大

10 个文件的 zip 里,每个文件都要写自己的本地头和中央目录记录,1742 字节里相当一部分是这些结构。tar.gz 只有一个 gzip 头,324 字节里几乎全是压缩后的数据。

这个差距在 10000 个文件上被放大

小目录差 5.4 倍,10000 个文件时差到 7.7 倍。文件越多,zip 的每文件开销叠得越厚,而 tar.gz 的头部是固定的。

几个真踩过的点

下面三条在这次测试里真实出现,附当时的处理方式。

现象原因处理
压缩时刷出一屏 INFO 行默认逐个文件打日志加 -q 或把输出重定向,否则管道里全是提示
目标文件已存在时停下等确认默认交互式脚本里加 -y 直接覆盖
解压到当前目录而不是指定目录-d 参数位置写错把 -d 放在输入文件之后,跟目标目录名

输出会淹没终端

每个文件一行 INFO,终端滚动几秒才停。如果把这批输出直接接给下游解析,INFO 行会让解析失败;加上重定向或换 list 这类只出结果的子命令才不会串味。

用 7z 打 zip 时参数顺序不能错

7z a -tzip -mx=6 s7.zip 源目录 里 -t 和 -mx 必须在输出文件名之前,写到后面会被当成文件名的一部分,压缩级别不生效。

什么场景值得上

手上有一堆不同后缀的压缩包、又不想为每种格式记一套参数时,一个 6.4 MB 的 exe 全包了。

场景合适度说明
批量处理多种格式高14 种格式扩展名即参数
脚本里一键打包高一条命令,-y 免交互
追求压缩速度低zip 比 7-Zip 慢 2.7 倍
需要图形界面低纯命令行,没有窗口

它不替代 7-Zip

论吞吐 7-Zip 在 zip 上快 2.7 倍,论格式覆盖 7-Zip 加上插件也不差。ouch 的位置是「命令行里最省心的一步」,不是「最快的压缩器」。

授权与费用

MIT 许可,个人和商业环境都不收费。源码在 GitHub 上,主要语言 Rust,release 覆盖 Windows、macOS、Linux 三平台。