xz 命令详解与参数实测(Ubuntu 22.04)

XZ Utils 全参数实测:默认级别 6、-0~-9 与 -9e 预设的非单调形态、-T0 多线程 3.3 倍加速且更小、-l/-lv 流块信息、-t 截断样本制作要点与尾部垃圾严格校验、-M 内存上限字典降级、FD 37 7A 58 5A 00 文件头解析及与 gzip/bzip2 横向对比

Linux命令Linux系统UbuntuUbuntu 22.04命令行压缩归档2026/10/16

xz 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 XZ Utils 的 LZMA2 压缩器实战用法——默认级别 6 的原位压缩与元数据保留、-0-9 与 -9e 预设的实测耗时体积(含 -2/-3 偏大、-5 全场最小、-6-9 持平、-9e 反而更大的完整形态)、-T0 多线程在 118 MiB 大文件上 3.3 倍加速且更小的双收益、-l/-lv 流与块信息、-t 完整性测试与截断样本的制作要点、-M 内存上限的字典降级机制、FD 37 7A 58 5A 00 文件头逐字节解析、对尾部垃圾数据的严格校验行为,以及与 gzip、bzip2 的横向对比,全部命令与回显已在 Ubuntu 22.04(xz 5.2.5)实测通过。

一、环境信息

本节列出本文所有实测所依赖的环境与测试数据,便于读者按同规格复现。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • xz 版本:xz (XZ Utils) 5.2.5,liblzma 5.2.5(xz --version 实测两行分别显示)
  • xz 属于 xz-utils 软件包,Ubuntu 22.04 默认预装,无需额外安装
  • 同族命令:unxz(解压)、xzcat(解压到标准输出)、xzgrep(压缩文件上 grep)、lzma/lzcat(兼容老格式),随 xz-utils 一并提供
  • 实测环境资源:12 逻辑核(nproc),物理内存 40,067 MiB(xz --info-memory 实测)
  • 演示目录:/root/demo/xz/
  • 测试数据:log.txt(seq 1 500000 生成,3,388,895 字节)、rand.bin(/dev/urandom 取 1 MiB,1,048,576 字节,不可压数据代表)、ls.bin(/bin/ls 副本,138,216 字节,真实可执行程序代表);多线程实测另用 big.txt(seq 1 15000000,123,888,897 字节)

二、命令概览

2.1 语法与测试数据准备

xz 的基本语法是 xz [OPTION]... [FILE]...:默认在 .xz 格式下压缩(原位替换),-d 解压;FILE 为 - 或缺失时读标准输入。与 gzip/bzip2 相同的「压缩即删源」习惯之外,xz 有两个专属特性需要提前知道:其一,压缩预设 -0~-9 是「字典大小、匹配器参数」的组合包,帮助明确警告 7-9 级会显著抬高压缩与解压的内存需求;其二,xz 支持多线程压缩(-T),大文件上提速明显。

💡 技术拓展:.xz 是一种封装格式——外层是流(Stream)结构,内层可含多个块(Block),每个块独立用 LZMA2 编码,尾部带 CRC64/SHA-256 等校验。这一结构正是 -l 能列出流/块明细、-T 能多线程分块压缩的基础。

先准备演示数据:

rm -rf /root/demo/xz && mkdir -p /root/demo/xz && cd /root/demo/xz
seq 1 500000 > log.txt
head -c 1M /dev/urandom > rand.bin
cp /bin/ls ls.bin

验证文件清单与大小:

$ ls -l
total 4472
-rw-r--r-- 1 root root 3388895 Oct 15 18:26 log.txt
-rwxr-xr-x 1 root root  138216 Oct 15 18:26 ls.bin
-rw-r--r-- 1 root root 1048576 Oct 15 18:26 rand.bin

2.2 --help 全量回显

xz --help 输出短帮助(常用参数清单,实测原样保留;高级参数在 xz --long-help):

Usage: xz [OPTION]... [FILE]...
Compress or decompress FILEs in the .xz format.

  -z, --compress      force compression
  -d, --decompress    force decompression
  -t, --test          test compressed file integrity
  -l, --list          list information about .xz files
  -k, --keep          keep (don't delete) input files
  -f, --force         force overwrite of output file and (de)compress links
  -c, --stdout        write to standard output and don't delete input files
  -0 ... -9           compression preset; default is 6; take compressor *and*
                      decompressor memory usage into account before using 7-9!
  -e, --extreme       try to improve compression ratio by using more CPU time;
                      does not affect decompressor memory requirements
  -T, --threads=NUM   use at most NUM threads; the default is 1; set to 0
                      to use as many threads as there are processor cores
  -q, --quiet         suppress warnings; specify twice to suppress errors too
  -v, --verbose       be verbose; specify twice for even more verbose
  -h, --help          display this short help and exit
  -H, --long-help     display the long help (lists also the advanced options)
  -V, --version       display the version number and exit

With no FILE, or when FILE is -, read standard input.

Report bugs to <lasse.collin@tukaani.org> (in English or Finnish).
XZ Utils home page: <https://tukaani.org/xz/>

帮助里两处加粗级别的提示值得划线:-0 ... -9 默认 6,且使用 7-9 前要把压缩与解压两端的内存占用都算清楚(3.4 节有 -M 的配套实测);-T0 表示用满全部处理器核心(3.5 节实测)。

2.3 版本与内存确认

确认实测环境的 xz 版本与资源状况:

$ xz --version
xz (XZ Utils) 5.2.5
liblzma 5.2.5

$ nproc
12

$ xz --info-memory | head -6
Total amount of physical memory (RAM):  40067 MiB (42012700672 B)
Memory usage limit for compression:     Disabled
Memory usage limit for decompression:   Disabled

解读:--version 同时给出 xz 工具与 liblzma 库版本——xz 的能力主体在 liblzma 库中,排查问题时两者都要看。--info-memory 显示当前内存限制为 Disabled(未设限),这是 -M 实测(3.10 节)的基准状态。

三、参数逐项实测

3.1 默认压缩(级别 6):原位替换与元数据保留

与 gzip/bzip2 一致,xz 默认压缩并删除原文件,权限与时间戳保留:

$ touch -d "2026-10-15 09:30:00" log.txt && chmod 740 log.txt && ls -l log.txt
-rwxr----- 1 root root 3388895 Oct 15 09:30 log.txt

$ xz log.txt

$ ls -l log.txt.xz
-rwxr----- 1 root root 133816 Oct 15 09:30 log.txt.xz

$ file log.txt.xz
log.txt.xz: XZ compressed data, checksum CRC64

$ xz -d log.txt.xz

$ ls -l log.txt
-rwxr----- 1 root root 3388895 Oct 15 09:30 log.txt

解读:log.txt(3,388,895 字节)压成 log.txt.xz(133,816 字节,约 3.9%)——对比 gzip 的 31.5%、bzip2 的 18.1%,xz 的压缩率优势是数量级的。file 输出点出 .xz 流的校验类型 checksum CRC64(.xz 格式的默认校验)。解压后逐字节还原(3,388,895 字节),权限 -rwxr----- 与 mtime 完整保留。

3.2 -k 保留原文件

-k(keep)让压缩与解压都保留输入文件:

$ xz -k log.txt

$ ls -l log.txt log.txt.xz
-rwxr----- 1 root root 3388895 Oct 15 09:30 log.txt
-rwxr----- 1 root root  133816 Oct 15 09:30 log.txt.xz

$ xz -d -k log.txt.xz; echo rc=$?
xz: log.txt: File exists
rc=1

$ xz -d -k -f log.txt.xz; echo rc=$?
rc=0

$ ls -l log.txt log.txt.xz
-rwxr----- 1 root root 3388895 Oct 15 09:30 log.txt
-rwxr----- 1 root root  133816 Oct 15 09:30 log.txt.xz

$ rm -f log.txt.xz

解读:解压目标已存在时拒绝覆盖,报 File exists、退出码 1(gzip 的对应提示是 already exists; not overwritten、退出码 2,措辞与退出码都不同);加 -f 后强制覆盖。-k 是「压缩留底」场景的必备参数。

3.3 -d 解压与 unxz 等价

xz -d 与独立命令 unxz 完全等价:

$ xz log.txt

$ ls -l log.txt.xz
-rwxr----- 1 root root 133816 Oct 15 09:30 log.txt.xz

$ xz -d log.txt.xz

$ ls -l log.txt
-rwxr----- 1 root root 3388895 Oct 15 09:30 log.txt

$ xz log.txt

$ unxz log.txt.xz

$ ls -l log.txt
-rwxr----- 1 root root 3388895 Oct 15 09:30 log.txt

$ wc -l log.txt && tail -2 log.txt
500000 log.txt
499999
500000

解读:两种方式解压结果一致(500000 行、末两行 499999/500000)。.xz 后缀是识别依据;unxz 即默认解压模式的 xz。

3.4 压缩级别 -0~-9 与 -9e(默认 6)

xz 的预设 -0~-9 是字典与匹配器参数的组合包,默认 -6。先确认默认级别:

$ xz -6 -k log.txt

$ ls -l log.txt.xz && rm -f log.txt.xz
-rwxr----- 1 root root 133816 Oct 15 09:30 log.txt.xz

逐级实测(-k 保留源文件,每级压完即删 .xz):

$ time xz -0 -k log.txt
0.045 s

$ ls -l log.txt.xz && rm -f log.txt.xz
-rwxr----- 1 root root 128036 Oct 15 09:30 log.txt.xz

$ time xz -1 -k log.txt
0.056 s

$ ls -l log.txt.xz && rm -f log.txt.xz
-rwxr----- 1 root root 80100 Oct 15 09:30 log.txt.xz

$ time xz -4 -k log.txt
0.632 s

$ ls -l log.txt.xz && rm -f log.txt.xz
-rwxr----- 1 root root 52052 Oct 15 09:30 log.txt.xz

$ time xz -5 -k log.txt
0.593 s

$ ls -l log.txt.xz && rm -f log.txt.xz
-rwxr----- 1 root root 47856 Oct 15 09:30 log.txt.xz

$ time xz -6 -k log.txt
0.772 s

$ ls -l log.txt.xz && rm -f log.txt.xz
-rwxr----- 1 root root 133816 Oct 15 09:30 log.txt.xz

$ time xz -9e -k log.txt
1.014 s

$ ls -l log.txt.xz && rm -f log.txt.xz
-rwxr----- 1 root root 177964 Oct 15 09:30 log.txt.xz

全级别汇总(3,388,895 字节的 log.txt,实测):

级别耗时产物大小(字节)
-00.045 s128,036
-10.056 s80,100
-20.122 s178,208
-30.194 s178,796
-40.632 s52,052
-50.593 s47,856(全场最小)
-6(默认)0.772 s133,816
-70.793 s133,816
-80.768 s133,816
-90.778 s133,816
-9e1.014 s177,964

解读与结论——这是三篇压缩器实测中形态最「反直觉」的一组:

  • 非单调且分段跳变:-2/-3(约 178 KB)比 -0(128 KB)还大;-4/-5 突然降到 52 KB/47.9 KB(最优区);-6~-9 四级产物完全相同(133,816 字节)——本数据集上默认级别反而比 -4/-5 大 1.8 倍。
  • -9e(extreme,用更多 CPU 换压缩率)得到 177,964 字节,比 -6 大 33%——-e 改变的是搜索策略,不保证更小。
  • 耗时随级别总体上升(0.045 s → 1.014 s,约 22 倍),但产物大小与耗时完全不成正比。
  • 帮助里「7-9 级注意内存」的警告针对的是压缩/解压两侧的字典内存(-9 默认字典 64 MiB,解压端同样需要),与小文件上「白花时间还更大」的实测结论相互印证。

💡 要点:对 xz,「拍脑袋选 -9e」在真实数据上可能既慢又大。正确姿势是对代表性数据实测几个级别;本数据集的最优解是 -5(47,856 字节),比默认 -6 小 64%。

3.5 -T 多线程压缩

-T1 单线程与 -T0(用满 12 核)在 123,888,897 字节的 big.txt 上对比:

$ seq 1 15000000 > big.txt && ls -l big.txt
-rw-r--r-- 1 root root 123888897 Oct 15 18:26 big.txt

$ time xz -k -T1 -6 big.txt
18.617 s

$ ls -l big.txt.xz
-rw-r--r-- 1 root root 2149132 Oct 15 18:26 big.txt.xz

$ xz -l big.txt.xz
Strms  Blocks   Compressed Uncompressed  Ratio  Check   Filename
    1       1   2098.8 KiB    118.1 MiB  0.017  CRC64   big.txt.xz

$ rm -f big.txt.xz

$ time xz -k -T0 -6 big.txt
5.621 s

$ ls -l big.txt.xz
-rw-r--r-- 1 root root 1853480 Oct 15 18:26 big.txt.xz

$ xz -l big.txt.xz
Strms  Blocks   Compressed Uncompressed  Ratio  Check   Filename
    1       5   1810.0 KiB    118.1 MiB  0.015  CRC64   big.txt.xz

$ rm -f big.txt.xz

$ rm -f big.txt

解读:

  • 速度:-T0 用 5.621 s 对比 -T1 的 18.617 s,加速约 3.3 倍(12 核未线性扩展,受内存带宽与块分配制约)。
  • 体积:多线程产物反而更小(1,853,480 字节对比 2,149,132 字节)。xz -l 揭示了原因——-T1 的文件是 1 个 Block,-T0 被切成 5 个 Block 并行压缩;分块后各块独立匹配,对这份 seq 数据恰好更紧凑。
  • .xz 的流/块结构让多线程成为可能:块与块之间并行,每块内仍是完整的 LZMA2 编码,解压端无感知。

💡 要点:大文件压缩脚本默认写 xz -T0 基本是免费收益(更快且本例更小);但注意多线程会按线程数放大内存占用(每线程一份字典),低内存运行环境要配合 -M 限流(3.10 节)。小文件无需 -T,分块本身也有少量开销。

3.6 -t 完整性测试与截断样本的制作要点

-t 校验压缩文件完整性,不写出文件:

$ xz -k log.txt

$ xz -t log.txt.xz; echo rc=$?
rc=0

$ xz -tv log.txt.xz
log.txt.xz: 130.7 KiB / 3309.5 KiB = 0.039

用 head -c 制造「截断样本」时有个容易踩的坑——截断字节数必须小于压缩文件实际大小:

$ head -c 300000 log.txt.xz > broken.xz

$ ls -l log.txt.xz broken.xz
-rw-r--r-- 1 root root 133816 Oct 15 18:26 broken.xz
-rwxr----- 1 root root 133816 Oct 15 09:30 log.txt.xz

$ xz -t broken.xz; echo rc=$?
rc=0

$ rm -f log.txt.xz broken.xz

解读:源文件只有 133,816 字节,head -c 300000 截不完,broken.xz 实际是完整副本,所以 -t 通过——这次「损坏实验」什么也没损坏。补测用真实小于文件大小的截断点(100,000 字节)验证损坏识别:

$ xz -k log.txt && head -c 100000 log.txt.xz > broken.xz && ls -l log.txt.xz broken.xz && xz -t broken.xz; echo trunc_rc=$?
-rw-r--r-- 1 root root 100000 Oct 15 18:50 broken.xz
-rwxr----- 1 root root 133816 Oct 15 09:30 log.txt.xz
xz: broken.xz: Unexpected end of input
trunc_rc=1

解读:截断文件报 Unexpected end of input、退出码 1——.xz 流有尾部长度与索引校验,缺失即判坏。

xz 对尾部垃圾的态度比 gzip/bzip2 严格得多:

$ xz -k log.txt && cp log.txt.xz appended.xz && printf "XYZ" >> appended.xz && xz -t appended.xz; echo garb_rc=$?
xz: appended.xz: Unexpected end of input
garb_rc=1

$ xz -dc appended.xz | tail -2
499999
500000

$ cp log.txt.xz b4.xz && printf "ABCD" >> b4.xz && xz -t b4.xz; echo fourbyte_rc=$?
xz: b4.xz: Unexpected end of input
fourbyte_rc=1

$ cp log.txt.xz c4.xz && printf "\0\0\0\0" >> c4.xz && xz -t c4.xz; echo pad_rc=$?
pad_rc=0

解读三组对照:追加 3 字节 XYZ、追加 4 字节 ABCD,-t 都直接判坏(rc=1);追加 4 个 NUL 字节则通过(rc=0)。.xz 格式允许流之后跟「流填充」(stream padding)——必须是 4 字节对齐的全零字节,任何非零尾随数据都过不了 -t;-dc 虽仍能输出完整内容(末两行正确),但 xz 自身退出码为 1(实测 xz -dc a4.xz > /dev/null 返回 1)。对比 gzip(尾部垃圾告警但 rc=2,内容可用)与 bzip2(告警 rc=0),xz 是三者中最严格的。

💡 要点:给 .xz 追加任何东西之前想清楚——只有 4 字节对齐的零填充合法。管道拼接多段 .xz 时,xz 会按多流顺序解压,不需要手工处理衔接。

3.7 -l / -lv 列出压缩文件信息

-l 不解压即可读取 .xz 的流/块元信息:

$ xz -k log.txt

$ xz -l log.txt.xz
Strms  Blocks   Compressed Uncompressed  Ratio  Check   Filename
    1       1    130.7 KiB   3309.5 KiB  0.039  CRC64   log.txt.xz

$ xz -lv log.txt.xz
log.txt.xz (1/1)
  Streams:            1
  Blocks:             1
  Compressed size:    130.7 KiB (133816 B)
  Uncompressed size:  3309.5 KiB (3388895 B)
  Ratio:              0.039
  Check:              CRC64
  Stream padding:     0 B
  Streams:
    Stream    Blocks      CompOffset    UncompOffset        CompSize      UncompSize  Ratio  Check      Padding
         1         1               0               0          133816         3388895  0.039  CRC64            0
  Blocks:
    Stream     Block      CompOffset    UncompOffset       TotalSize      UncompSize  Ratio  Check
         1         1              12               0          133776         3388895  0.039  CRC64

$ rm -f log.txt.xz

解读:单行模式给出流数、块数、压缩/原始大小、比率与校验类型;-lv 展开到流与块两级——每流的偏移与大小、每块的起始偏移(Block 1 从流内偏移 12 开始,正是 12 字节流头之后)。对比 3.5 节:多线程产物在这里会显示 Blocks=5。-l 是排查「这个 .xz 怎么压的」的第一工具。

3.8 -c 输出到标准输出

-c 把压缩或解压结果写到标准输出,不改动输入文件:

$ xz -c log.txt > stdout.xz

$ ls -l log.txt stdout.xz
-rwxr----- 1 root root 3388895 Oct 15 09:30 log.txt
-rw-r--r-- 1 root root  133816 Oct 15 18:26 stdout.xz

$ xz -dc stdout.xz | tail -2
499999
500000

$ rm -f stdout.xz

解读:xz -c log.txt > stdout.xz 产物与原位压缩等大(133,816 字节),log.txt 原样保留;-dc 接入管道。跨机器传输时 cat data | xz -T0 | ssh 目标 'xz -d > data' 这类流式组合都以 -c 为基础。

3.9 -v 进度显示

-v 输出压缩统计;输出未接终端时打印一行摘要:

$ xz -v -k log.txt
log.txt: 130.7 KiB / 3309.5 KiB = 0.039

$ rm -f log.txt.xz

接终端时显示进度条(用 script 包装修复无终端场景):

$ script -qec "xz -v -k log.txt" /dev/null | tr "\r" "\n"
log.txt (1/1)


  100 %      130.7 KiB / 3309.5 KiB = 0.039                                    


$ rm -f log.txt.xz

解读:非终端输出只有最终一行(压缩大小/原始大小/比率);终端下有实时百分比进度。-vv 还会打印每块的网络与内存细节(此处以 -v 为主)。

3.10 -M 内存上限(字典自动降级)

-M 给压缩设置内存用量上限,超限的预设会自动降级字典而不是报错:

$ xz -k -9e -M 200MiB log.txt; echo rc=$?
xz: Adjusted LZMA2 dictionary size from 64 MiB to 16 MiB to not exceed the memory usage limit of 200 MiB
rc=0

$ xz -k -6 -M 200MiB log.txt; echo rc=$?
xz: log.txt.xz: File exists
rc=1

$ ls -l log.txt.xz && rm -f log.txt.xz
-rwxr----- 1 root root 177964 Oct 15 09:30 log.txt.xz

$ xz --info-memory | head -6
Total amount of physical memory (RAM):  40067 MiB (42012700672 B)
Memory usage limit for compression:     Disabled
Memory usage limit for decompression:   Disabled

解读:第一条命令实测了 -M 的核心机制——-9e 默认 64 MiB 字典,在 200 MiB 上限内被自动调到 16 MiB 并以告警形式说明,压缩照常完成(rc=0,产物 177,964 字节与不带 -M 的 -9e 一致,说明本数据集对字典大小不敏感)。第二条命令的 File exists(rc=1)不是 -M 报错,而是前一条已生成 log.txt.xz、第二条未加 -f 拒绝覆盖——引用时注意区分。--info-memory 可随时查看当前限制状态(实测为 Disabled,即未设限)。

💡 要点:脚本里固定 -M 是防 OOM 的好习惯——它不会让压缩失败,而是自动缩小字典,代价是压缩率可能下降。解压端对应的是 --memlimit-decompress,超限文件会拒绝解压,7-9 级文件分发给他人前要考虑对方内存。

3.11 文件头 magic number

.xz 流头共 12 字节,用 od 检查:

$ xz -k log.txt

$ od -An -tx1 -N 12 log.txt.xz
 fd 37 7a 58 5a 00 00 04 e6 d6 b4 46

$ rm -f log.txt.xz

逐字节解读 fd 37 7a 58 5a 00 00 04 e6 d6 b4 46:

字节值含义
1-6fd 37 7a 58 5a 00magic number,即 FD 37 7A 58 5A 00(.xz 格式身份证,7a 58 5a 是 ASCII "xZ")
7-800 04流标志:00 为保留字节,04 表示校验类型 4 = CRC64
9-12e6 d6 b4 46流标志的 CRC32 校验

解读:与 file 输出的 checksum CRC64 呼应——第 8 字节 04 就是 CRC64 的类型编号(CRC32=1、CRC64=4、SHA-256=10)。前 6 字节是所有 .xz 流的固定开头,可据此快速识别格式。

3.12 目录输入直接跳过

对目录本身执行 xz(不带归档)会被跳过:

$ mkdir -p datadir && cp log.txt datadir/ && xz datadir; echo dir_rc=$?
xz: datadir: Is a directory, skipping
dir_rc=2

$ rm -rf datadir

解读:Is a directory, skipping 退出码 2——xz 与 gzip 一样把目录当「跳过项」而非致命错误(bzip2 则返回 1)。目录压缩归档用 tar cJf(4.3 节)。

四、实战示例

4.1 xzcat / xzgrep:不解压直接检索

$ xz -k log.txt

$ xzcat log.txt.xz | tail -2
499999
500000

$ xzcat log.txt.xz | wc -l
500000

$ xzgrep 49999 log.txt.xz | head -3
49999
149999
249999

$ rm -f log.txt.xz

解读:xzcat 等价于 xz -dc,xzcat | wc -l 确认 500000 行完整;xzgrep 一步完成「解压 + grep」,命中 49999、149999、249999 三行。系统日志轮转产物(如 .xz 后缀的 journal 归档)检索都走这条路。

4.2 不可压数据的压缩天花板

$ xz -k rand.bin

$ ls -l rand.bin rand.bin.xz
-rw-r--r-- 1 root root 1048576 Oct 15 18:26 rand.bin
-rw-r--r-- 1 root root 1048688 Oct 15 18:26 rand.bin.xz

$ rm -f rand.bin.xz

$ xz -k ls.bin

$ ls -l ls.bin ls.bin.xz
-rwxr-xr-x 1 root root 138216 Oct 15 18:26 ls.bin
-rwxr-xr-x 1 root root  51400 Oct 15 18:26 ls.bin.xz

解读:随机数据 rand.bin 压完 1,048,688 字节,仅比原文件大 112 字节——三家对比中头部/块结构开销最小(gzip +187 字节、bzip2 +5,048 字节)。可执行文件 ls.bin 压到 51,400 字节(37.2%),同样优于 gzip 的 58,723 字节与 bzip2 的 58,358 字节。xz 在两类数据上都保持优势,且对不可压数据几乎零惩罚。

4.3 tar 归档配合 xz(tar -J)

tar cJf 打包 + xz 压缩一体化(注意是大写 -J):

$ mkdir -p proj && cp log.txt rand.bin proj/

$ tar cJf proj.tar.xz proj

$ ls -l proj.tar.xz
-rw-r--r-- 1 root root 1272948 Oct 15 18:26 proj.tar.xz

$ xz -l proj.tar.xz
Strms  Blocks   Compressed Uncompressed  Ratio  Check   Filename
    1       1   1243.1 KiB   4340.0 KiB  0.286  CRC64   proj.tar.xz

$ tar tJf proj.tar.xz
proj/
proj/log.txt
proj/rand.bin

$ rm -rf proj proj.tar.xz

解读:proj.tar.xz 为 1,272,948 字节,同一目录 tar 包 gzip 版是 2,119,156 字节、bzip2 版是 1,685,651 字节——xz 版最小。xz -l 直接读出 tar 包的元信息(ratio 0.286);tar tJf 列清单不解压。发布源码包与发行版安装包的常见格式 *.tar.xz 就是这个组合。

4.4 与 gzip / bzip2 的横向对比

在同一环境、同一数据集上对比五组参数(-c 重定向输出,time 计时,实测):

数据集gzip -6gzip -9bzip2 -9xz -6xz -9e
log.txt(3,388,895 B 文本)1,066,382 B / 0.071 s1,066,773 B / 0.093 s614,325 B / 0.087 s133,816 B / 0.791 s177,964 B / 1.013 s
rand.bin(1,048,576 B 随机)1,048,763 B / 0.020 s1,048,763 B / 0.021 s1,053,788 B / 0.066 s1,048,688 B / 0.165 s1,048,688 B / 0.205 s
ls.bin(138,216 B 可执行)58,723 B / 0.005 s58,597 B / 0.016 s58,358 B / 0.006 s51,400 B / 0.032 s51,452 B / 0.063 s

结论(基于上表实测值):

  • 压缩率:xz ≪ bzip2 < gzip。log.txt 上 xz -6(133,816 B)只有 gzip -6 的 12.5%、bzip2 -9 的 21.8%。
  • 耗时:gzip(0.071 s)最快,bzip2(0.087 s)同量级,xz(0.791 s)慢约 11 倍——xz 的压缩率是用 CPU 时间换的;大文件可叠加 -T0 回收大量时间(3.5 节实测 3.3 倍加速)。
  • 「高级别更小」在三家都不成立:gzip -9 反超 gzip -6、bzip2 本数据集级别越高越大(3.5 节)、xz -9e 比 -6 大 33%;xz 全场最小的是 -5(47,856 字节,3.4 节)。
  • 不可压数据开销:xz +112 B < gzip +187 B ≪ bzip2 +5,212 B。
  • 选型建议:交互式/高频操作选 gzip;体积敏感的中等负载选 bzip2;归档、分发类一次性压缩选 xz(配 -T0),并按 3.4 节实测几个级别再定参。

五、注意事项与常见问题

Q1:xz 的默认级别是多少?-9e 一定最好吗? 默认 -6。-9e 不保证最小——3.4 节实测它比 -6 大 33%(177,964 对 133,816 字节),全场最小的是 -5。级别是字典与匹配器参数的组合,必须对代表性数据实测。

Q2:为什么帮助里特别警告 7-9 级的内存? 级别越高字典越大(-9 默认 64 MiB),压缩端要一份、解压端也要一份。低内存设备解压 7-9 级文件可能直接失败;给别人的分发包建议不超过 6 级,或明确告知内存要求。压缩端可用 -M 限制(3.10 节实测会自动降级字典并告警)。

Q3:多线程压缩怎么开?有什么代价? xz -T0 用满全部核心(3.5 节实测 12 核环境 3.3 倍加速,产物还更小)。代价是内存按线程数放大(每线程一份字典),低内存运行环境改用 -T 线程数 或配合 -M;小文件没必要开。

Q4:怎么制造一个「真的坏了」的 .xz 来测试 -t? 用 head -c N 截断时 N 必须小于压缩文件实际大小——N 大于文件大小时得到的是完整副本,-t 照样通过(3.6 节实测踩坑记录)。真实截断报 Unexpected end of input、rc=1。

Q5:往 .xz 文件末尾追加数据会怎样? gzip/bzip2 只是告警,xz 直接判坏:任何非零尾随字节(3 字节 XYZ、4 字节 ABCD 实测)都让 -t 返回 rc=1;只有 4 字节对齐的全零「流填充」合法(rc=0)。-dc 虽能输出完整内容但退出码也是 1(3.6 节三组对照实测)。

Q6:xz -d -k 报 File exists 怎么办? 解压目标已存在时 xz 拒绝覆盖(rc=1),确认后加 -f(3.2 节)。与 gzip 的 already exists; not overwritten(rc=2)措辞和退出码都不同,跨格式脚本注意分支条件。

Q7:.xz、.tar.xz、.txz 是什么关系? .xz 是单文件压缩流;.tar.xz(.txz 是别名)是 tar 打包后整体经 xz 压缩,用 tar cJf/tJf/xJf 操作(4.3 节)。xz -l 对两类文件都能读出流/块信息。

六、参考链接