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 + 压缩算法) 内置压缩
随机访问 不支持(需全解压) 支持(直接读取包内单个文件)
适用场景 系统包、固件、备份 跨平台分发、资源包
我的建议:做 Android/Linux 全量包,无脑选 tar。如果你需要分发给 Windows 用户,可以额外打一个 zip 包,但内部核心包一定用 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
注意:xz 解压速度也不快。如果你在目标设备上解压,设备性能差的话,解压时间可能比刷写时间还长。我曾经在低端设备上踩过这个坑,后来改回了 gzip。

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 知识结构图

下面这张图把打包策略的核心逻辑串起来了,你可以对照着看:

文件打包策略知识结构 打包策略选择 tar 打包 zip 打包 gzip 压缩 bzip2 压缩 xz 压缩 内置压缩 分卷打包 tar + split 分卷 zip -s 分卷 核心选择逻辑 1. 系统包/固件/备份 → tar + gzip/xz 2. 跨平台分发 → zip 3. 超大包 → 分卷打包(tar+split 或 zip -s)

4.5 实战建议

最后,给你几个我实际项目里总结出来的建议:

  • 别迷信最高压缩率。压缩率越高,耗时越长。在 CI 流水线上,时间就是金钱。我一般默认用 gzip,只有归档时才上 xz。
  • 分卷大小要合理。太小的分卷(比如 1MB)会导致文件数量爆炸,管理困难。太大又失去了分卷的意义。我一般按 100MB~500MB 切分,具体看传输通道的限制。
  • 分卷后一定要做校验。分卷传输容易丢包,合并前建议用 md5sum 或 sha256sum 校验每个分卷的完整性。这个我们下一章会详细讲。
  • 别忘了测试解压。我曾经打了一个 xz 包,在 PC 上解压没问题,结果到目标设备上解压到一半内存爆了。嗯,从那以后我每次都会在目标环境上做解压测试。
重要提醒:分卷打包时,split 输出的文件名默认不带后缀。合并时用 cat 按顺序合并即可,千万别用 tar -xzf 直接解分卷文件,那是解不出来的。