4. 文件打包策略:tar与zip的选择、压缩算法对比
做全量包,打包和压缩是绕不开的基础操作。你可能觉得这有什么好讲的?不就是打个包吗?嗯,我以前也这么想,直到有一次在产线上因为选错了压缩算法,导致整批包的体积超标,差点延误发版。从那以后,我对打包策略就格外上心。
这一章,我们就来聊聊 tar 和 zip 怎么选,gzip、bzip2、xz 这些压缩算法到底差在哪,以及分卷打包这种实用技巧。
4.1 tar vs zip:核心差异
先看一个最基础的问题:用 tar 还是 zip?
我个人习惯,在 Linux 环境下做系统级全量包,首选 tar。为什么?因为 tar 能完整保留文件的权限、属主、软链接、硬链接这些元信息。你想想看,一个系统包如果解压出来权限全丢了,那基本就是废的。
zip 呢?它更通用,跨平台友好,Windows 和 macOS 都能直接解。但 zip 对 Linux 文件权限的支持很弱,尤其是 setuid、setgid、粘滞位这些,zip 存不住。
| 对比维度 | tar | zip |
|---|---|---|
| 文件权限保留 | 完整保留(权限、属主、ACL) | 仅保留基本权限,易丢失 |
| 软/硬链接 | 完美支持 | 不支持 |
| 跨平台性 | Linux 原生,Windows 需额外工具 | 全平台原生支持 |
| 压缩集成 | 分离式(tar + 压缩算法) | 内置压缩 |
| 随机访问 | 不支持(需全解压) | 支持(直接读取包内单个文件) |
| 适用场景 | 系统包、固件、备份 | 跨平台分发、资源包 |
4.2 压缩算法对比:gzip vs bzip2 vs xz
tar 本身不压缩,它只是把文件粘成一个。真正的压缩靠的是外部算法。我常用的就三种:gzip、bzip2、xz。它们各有脾气。
4.2.1 gzip:快,但压缩率一般
gzip 是我用得最多的。为什么?快。在 CI/CD 流水线上,压缩速度往往比压缩率更重要。你想想,每次发版都要等十几分钟压缩,谁也受不了。
# 打包并 gzip 压缩
tar -czf full_package.tar.gz /system /vendor
# 解压
tar -xzf full_package.tar.gz
gzip 的压缩率大概在 2~4 倍左右,对文本文件效果不错,对已压缩的文件(如 .jpg、.mp4)基本无效。
4.2.2 bzip2:折中选择
bzip2 的压缩率比 gzip 高 10%~20%,但速度慢不少。我在项目中遇到过需要压缩日志归档的场景,用 bzip2 能省不少磁盘空间。
# 打包并 bzip2 压缩
tar -cjf full_package.tar.bz2 /system /vendor
# 解压
tar -xjf full_package.tar.bz2
不过说实话,现在用 bzip2 的人越来越少了。xz 的出现让 bzip2 的位置有点尴尬。
4.2.3 xz:压缩率之王,但慢
xz 的压缩率能到 5~8 倍,比 gzip 强太多了。但代价也很明显——慢,非常慢。我曾经用 xz 压缩一个 2GB 的系统分区,等了将近 10 分钟。
# 打包并 xz 压缩
tar -cJf full_package.tar.xz /system /vendor
# 解压
tar -xJf full_package.tar.xz
4.2.4 算法对比一览
| 算法 | 压缩率 | 压缩速度 | 解压速度 | 内存占用 | 典型后缀 |
|---|---|---|---|---|---|
| gzip | 2~4x | 快 | 快 | 低 | .tar.gz / .tgz |
| bzip2 | 3~5x | 中等 | 中等 | 中 | .tar.bz2 |
| xz | 5~8x | 慢 | 中等 | 高 | .tar.xz |
- 日常开发/测试包:gzip,快就完事了。
- 归档/备份:xz,省空间。
- 分发给客户/产线:看设备性能,性能好上 xz,否则 gzip。
4.3 分卷打包技巧
有时候包太大了,单文件没法存,或者传输工具有大小限制。这时候就需要分卷打包。
tar 本身不支持分卷,但我们可以借助 split 命令来实现。说白了就是先打包,再切分。
# 先打包成 tar.gz,再按 100MB 分卷
tar -czf - /system /vendor | split -b 100M - full_package.tar.gz.part_
# 合并并解压
cat full_package.tar.gz.part_* | tar -xzf -
这里有个细节:split 的 -b 参数指定每卷大小,- 表示从标准输入读取,full_package.tar.gz.part_ 是输出文件的前缀。合并时用 cat 把所有分卷串起来,再通过管道喂给 tar。
-,结果 split 把文件名当成了输入文件,打出来的分卷全是空的。嗯,从那以后我每次都会检查分卷的大小。
zip 自带分卷功能,用 -s 参数就行:
# 按 100MB 分卷压缩
zip -s 100m -r full_package.zip /system /vendor
# 解压时先合并再解
zip -s 0 full_package.zip --out full_package_merged.zip
unzip full_package_merged.zip
zip 的分卷更友好,但前面说了,zip 不适合系统包。所以我的建议是:系统包用 tar + split,普通资源包用 zip 分卷。
4.4 知识结构图
下面这张图把打包策略的核心逻辑串起来了,你可以对照着看:
4.5 实战建议
最后,给你几个我实际项目里总结出来的建议:
- 别迷信最高压缩率。压缩率越高,耗时越长。在 CI 流水线上,时间就是金钱。我一般默认用 gzip,只有归档时才上 xz。
- 分卷大小要合理。太小的分卷(比如 1MB)会导致文件数量爆炸,管理困难。太大又失去了分卷的意义。我一般按 100MB~500MB 切分,具体看传输通道的限制。
- 分卷后一定要做校验。分卷传输容易丢包,合并前建议用 md5sum 或 sha256sum 校验每个分卷的完整性。这个我们下一章会详细讲。
- 别忘了测试解压。我曾经打了一个 xz 包,在 PC 上解压没问题,结果到目标设备上解压到一半内存爆了。嗯,从那以后我每次都会在目标环境上做解压测试。
cat 按顺序合并即可,千万别用 tar -xzf 直接解分卷文件,那是解不出来的。