ByteScope

XZ 檔案格式

XZ 壓縮的資料,通常使用 LZMA2 演算法。

MIME 類型
application/x-xz
副檔名
.xz
分類
壓縮與封存

Magic number(檔案簽章)

0x00000000FD377A585A00·7zXZ·XZ magic

關於 XZ 格式

XZ 把 LZMA2 包進一個帶完整性檢查的容器,能得到很高的壓縮率,因此用於軟體發佈與核心映像檔。6 位元組的 magic number 是 FD 37 7A 58 5A 00。跟它取代掉的那些格式不同,xz 是一個正經的容器,不是蓋在串流上的一層標頭:它有串流標頭和一份對應的串流頁尾,中間是一個或多個區塊,每個區塊有自己的標頭與 CRC,檔尾還有一份索引,列出每個區塊壓縮前後的大小。有那份索引,讀取端才能在不解壓縮的情況下驗證檔案、或在裡面 seek — 而這也正是為什麼被截斷的 .xz 根本無從檢查。

檔頭結構,一個位元組一個位元組看

位移長度欄位意義
06Header magic bytesFD 37 7A 58 5A 00。第 1 到 4 個位元組讀成 ASCII 就是 '7zXZ',這是它跟 7-Zip 自家格式混淆不清的長期來源;開頭那個 FD 刻意落在 ASCII 之外,而結尾那個 00 則讓檔案在任何文字模式傳輸裡大聲壞掉。
62Stream flags第一個位元組是保留的,必須是 00。第二個位元組的低四個位元指名完整性檢查方式:0 是沒有、1 是 CRC-32、4 是 CRC-64、10 是 SHA-256。標準工具寫出來的檔案讀到的是 00 04,因為預設是 CRC-64。
84CRC-32 of the stream flags小端序,只涵蓋位移 6 那兩個位元組。它存在的目的,是讓讀取端在還沒解出任何東西之前,就能信任自己要套用哪一種檢查方式。
121Block header size編碼過的值:真正的大小是「這個值加一再乘以四」,所以 04 代表二十個位元組的區塊標頭。這裡是 00 有特殊意義 — 代表沒有更多區塊了,索引就從這個位移開始。
131Block flags低兩個位元是濾波器數量減一;位元 6 表示後面有一個壓縮大小欄位,位元 7 表示有未壓縮大小欄位。典型的單一濾波器、兩個大小都在的區塊,讀到的是 C0。
variablevariableBlock sizes and filter flags在區塊標頭裡,依序是:選用的壓縮與未壓縮大小,以多位元組的變動長度整數表示,接著是濾波器鏈 — LZMA2 的濾波器 id 是 0x21,帶一個編碼字典大小的屬性位元組 — 然後補零到四的倍數,最後是區塊標頭自己的 CRC-32。
variablevariableIndex在最後一個區塊之後:每個區塊一筆記錄,給出它壓縮前後的大小,補齊到四的倍數,後面跟著它自己的 CRC-32。`xz --list` 讀的就是這個,也是為什麼 xz 能在不解壓縮的情況下報出檔案內容。
-124Stream footer CRC-32小端序,涵蓋它後面那六個頁尾位元組。頁尾固定十二個位元組,所以跟 ZIP 的結尾記錄不同,永遠不必倒著掃描去找它。
-84Backward size小端序;真正的索引大小是「這個值加一再乘以四」。索引是十二個位元組的檔案,這裡存的是 02 00 00 00。就是它讓索引能從檔尾找到,也因此讓整個格式可以 seek。
-42Stream flags (copy)位移 6 和 7 那兩個位元組的逐位元組複本,好讓一個從檔尾開始讀的解碼器,得到跟標頭宣告一樣的檢查方式。兩邊對不上,代表檔案被動過手腳或被接錯了。
-22Footer magic 'YZ'59 5A。每個完好的 .xz 都以這兩個位元組結尾;只要它們不是最後兩個位元組,這個檔案就是被截斷了,前面的資料看起來再合法都不改變這件事。

怎麼跟長得像的格式分開

容易搞混的怎麼分
7-Zip這是這個格式自己招來的混淆。.xz 開頭是 FD 37 7A 58 5A 00,其中 '7z' 坐在位移 1 和 2;真正的 .7z 則是位移 0 就是 37 7A BC AF 27 1C。所以同樣那兩個位元組在兩種格式裡都出現,只差一格,而一個隨手搜尋 '7z' 的做法兩邊都會中。它們是毫無關係的格式:.7z 是帶目錄的多檔案封存檔,.xz 是單一條壓縮串流。
lzma (LZMA_Alone)它的前身,也是 .lzma 檔案為什麼那麼難辨識的原因:它根本沒有 magic number。標頭是十三個位元組 — 一個屬性位元組(通常是 5D),接四個位元組的小端序字典大小,再接八個位元組的小端序未壓縮大小,未知時就是重複的 FF。真實檔案讀起來是 5D 00 00 80 00 後面接八個 FF 位元組,這就是它最接近簽章的東西了。
GZIP1F 8B 對上 FD 37 7A 58 5A 00,而且結構上比這暗示的差得更遠:gzip 是蓋在串流上的一層標頭、沒有索引,而 xz 在檔尾保有一份區塊索引,因此不必解壓縮就能列出內容與驗證。
Zstandard現代的對手。28 B5 2F FD 對上 xz 的 magic。在最高設定下 xz 仍然壓得比較小,但 Zstandard 解壓縮快好幾倍、壓縮也快得多 — 這就是為什麼套件管理器一直在往那邊遷移。
TAR一個 .tar.xz 和「用 xz 壓了單一個檔案」是同一種格式。解壓縮之後看結果的位移 257,第一個 512 位元組 tar 標頭裡有沒有 'ustar' — .xz 容器本身沒有任何東西能分辨這兩者。

常見的壞法

  • 截斷。索引和頁尾都住在檔尾,所以被截斷的 .xz 既列不出內容也驗證不了,即使已經到手的每個區塊都解得出來。工具會回報非預期的輸入結束,而檔尾那兩個位元組的 'YZ',是用肉眼確認最快的方法。
  • 區塊本體裡翻掉一個位元。預設的完整性檢查是 CRC-64,所以損壞會被抓到 — 但只在解壓縮之後,因為位移 8 的 CRC-32 和區塊標頭自己的 CRC 都只涵蓋中介資料。資料損壞嚴重時,LZMA2 通常在走到檢查碼之前就先以解碼錯誤失敗了。
  • 結尾的 NUL 位元組被剝掉。區塊和串流都是用零位元組補齊到四的倍數的,所以任何會修掉結尾 NUL 的傳輸或建置步驟,都會毀掉頁尾賴以存在的對齊。檔案照樣被認成 xz,然後在最後一刻失敗。
  • 串接起來的串流被當成一條來剖析。把 .xz 檔案接起來是合法的,中間還允許選用的零填充,而標準工具會把全部解出來。一個自己手寫、看到第一組頁尾 magic 就停的讀取端,會靜靜地把後面的東西全部丟掉。
  • 文字模式傳輸。標頭 magic 裡那個 00 的存在就是要讓這件事立刻失敗,而它也確實做到了 — 但同樣的轉換發生在串流更後面時,標頭是完好的,所以檔案會被正確辨識,只有在解碼走到損壞處時才失敗。

這個格式現在還在用嗎

XZ 是用在「壓一次、被下載很多次,而且下載才是昂貴那一段」的場合。核心的 tarball、發行版套件、原始碼釋出和容器基礎層,十幾年來都倚賴它,因為在高預設等級下,LZMA2 仍然是常見格式裡輸出最小的通用選擇。代價也是真的:壓縮很慢而且極度吃記憶體,而解壓縮的記憶體用量取決於寫入端選的字典大小,所以一個用預設等級 9 做出來的封存檔,開它要大約 64 MB — 這在嵌入式目標上是實打實的問題。這一點加上好幾倍的速度差距,正是 Zstandard 從 2019 年前後開始在套件管理器和檔案系統裡穩定取代它的原因。xz 仍然是第一選擇的地方,是靜態內容那種受頻寬限制的散佈;而任何會被反覆寫入或即時串流的東西,它都是很差的選擇。

在這個站上打開 XZ 檔

這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。

相關格式

容易和 XZ 搞混的格式,可以比對它們的開頭位元組。

格式開頭位元組副檔名
GZIP1F 8B.gz
BZIP242 5A 68.bz2
Zstandard28 B5 2F FD.zst
7-Zip37 7A BC AF 27 1C.7z

常見問題

檔案的 magic number 是什麼?

檔案開頭的前幾個位元組,不管檔名寫什麼,它標明的是真正的格式。PNG 一定以 89 50 4E 47 開頭,ZIP 則是 50 4B 03 04。作業系統、瀏覽器和 file 指令讀的都是這幾個位元組,而不是相信副檔名 — 這就是為什麼把檔案改名並不會改變它實際上是什麼。

我要怎麼自己檢查 magic number?

在 macOS 或 Linux 上,xxd -l 16 檔名 會印出前 16 個位元組;在 Windows 上,PowerShell 的 Format-Hex -Path 檔名 -Count 16。或者把檔案丟進本站的檔案類型辨識工具,它會在本機讀取位元組並告訴你是什麼格式,不會上傳任何東西。

為什麼兩種格式的 magic number 會一樣?

因為其中一種是建立在另一種之上。docx、xlsx、pptx、apk、jar 與 epub 骨子裡都是 ZIP 壓縮檔,所以全都以 ZIP 的簽章開頭;要分辨它們得看裡面的項目。Java class 檔和 macOS 的通用二進位檔都以 CA FE BA BE 開頭,靠緊接其後的欄位區分。

有完全沒有 magic number 的檔案嗎?

有。XML、HTML、JSON、SVG、CSV 這類以文字為基礎的格式沒有固定的位元組簽章,所以改用結構來辨識:開頭的 <?xml 宣告、<svg 元素,或是 { 後面接著帶引號的鍵。這種偵測是合理推測而非確定,因此本參考頁會把這些格式標示為結構偵測。

magic number 相符就代表檔案安全嗎?

不代表。它告訴你的是格式,不是內容是否無害 — 一個貨真價實的 PDF 或 docx 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

手上有檔案可能是 XZ?用檔案類型辨識工具查出來 — 它在本機讀取 magic number,不上傳任何東西。或者瀏覽所有格式。