ByteScope

7-Zip 檔案格式

7-Zip 壓縮檔,通常透過 LZMA/LZMA2 達到很高的壓縮率。

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

Magic number(檔案簽章)

0x00000000377ABCAF271C7z··'·7z magic

關於 7-Zip 格式

7z 是 7-Zip 的原生格式,支援強力的 LZMA2 壓縮、solid 封存與 AES-256 加密。簽章是 37 7A BC AF 27 1C。前三十二個位元組就是整份固定排版的全部:一個簽章、一個格式版本,加上一個指向真正標頭所在位置的指標。其他所有東西 — 檔名、大小、時間戳、檢查碼,以及資料是怎麼編碼的描述 — 全都坐在檔案另一端的那份標頭裡,而且通常它自己也是壓縮過的。中間沒有任何逐檔標頭,這就是 .7z 精簡的原因,也是為什麼一個受損的 .7z 比 ZIP 難搶救得多。

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

位移長度欄位意義
06Signature37 7A BC AF 27 1C。前兩個位元組是 ASCII 的 '7z' 兩個字母,所以它們會以看得懂的文字出現;後面四個是刻意挑的任意二進位值,好讓任何文字檔都不可能撞上。
61Format major version至今寫出來的每個封存檔都是 0。這裡要是改了,就代表結構不相容的新格式,所以讀取端把其他值當成拒收的理由,而不是一個警告。
71Format minor version現在的封存檔是 4。次版本是向後相容的增補,所以看得懂 0.4 的讀取端,比它舊的全部應付得來。
84Start header CRC-32小端序,剛好涵蓋位移 12 到 31 那二十個位元組。它保護的是其他一切所依賴的那個指標,所以讀取端在 seek 到任何地方之前,就能分得出是前綴壞了還是本體壞了。
128Next header offset一個小端序 64 位元位移,指向真正的標頭 — 從位移 32、也就是這份簽章標頭的結尾算起,不是從檔案開頭算起。在一個 200246 位元組的封存檔裡它讀到 F4 0D 03 00 00 00 00 00,也就是 200180,所以標頭從 200212 開始。
208Next header size那份標頭的長度,小端序 64 位元。它和位移合起來必須剛好落在檔案結尾:32 加 200180 加 34 是 200246,正是檔案的實際大小 — 這道算術是現成最快的完整性檢查。
284Next header CRC-32前兩個欄位所指向的那份標頭的檢查碼,小端序,所以那裡的損壞在任何剖析嘗試之前就會被偵測到。
32variablePacked streams壓縮資料本身,緊接在三十二個位元組的簽章標頭之後寫入。在 solid 封存檔裡,這是一條橫跨很多檔案的連續編碼串流,而不是一個檔案一條串流。
variablevariableHeader位置是 32 加上 next header offset:這是封存檔真正的目錄 — 名稱、大小、CRC、時間戳、屬性,以及描述怎麼把壓縮串流解出來的編碼器鏈。它通常自己也是 LZMA 壓縮過的,而開啟標頭加密時,它還會被加密。

怎麼跟長得像的格式分開

容易搞混的怎麼分
XZ真正會害人出錯的就是這一個。.xz 開頭是 FD 37 7A 58 5A 00,所以 37 7A 這兩個位元組出現在位移 1,而 ASCII 的 '7zXZ' 在 hex dump 裡清清楚楚。真正的 .7z 是位移 0 就 37 7A BC AF 27 1C。差一格,兩種毫無關係的格式:.7z 是帶目錄的多檔案封存檔,.xz 是單一條壓縮串流。
ZIP位元組上沒有任何共通處 — 50 4B 03 04 對上 37 7A BC AF 27 1C — 但兩者是同一個工具寫出來的,標錯名字的情況也一直在發生。結構上的差別在目錄住在哪裡、以及代價多少:ZIP 列出並抽出單一項目很便宜,而一個 solid 的 .7z 為了拿到一個檔案,可能得先解好幾 GB。
RAR5另一個高壓縮率的 Windows 壓縮工具,開頭是 52 61 72 21 1A 07 01 00。它們正面競爭;實務上的差別是 7z 是開放的、可以自由實作,而 RAR 是專有的,另外 RAR 有修復記錄而 7z 沒有。
Self-extracting .exe7-Zip 的自解壓縮封存檔是一個後面接著封存檔的 Windows 執行檔,所以位移 0 讀到的是 4D 5A('MZ'),而 37 7A BC AF 27 1C 簽章坐在檔案深處。任何會掃描簽章的 7z 讀取端仍然解得開它,這也是為什麼一個 .exe 可以安全地當成封存檔打開。

常見的壞法

  • 截斷,而且它比在 ZIP 上痛得多。前三十二個位元組裡的 next header offset 現在指到檔案結尾之外,於是什麼都列不出來 — 而且跟 ZIP 不同,這裡沒有逐檔的區域標頭可以往前掃,因為 .7z 根本就沒有。想部分救援,通常意味著用手把編碼器鏈猜出來。
  • 位移 8 的起始標頭 CRC 對不上。前三十二個位元組壞了,而實務上這幾乎一定代表有位元組被加在前面或被剝掉,而不是原地翻了一個位元 — 因為那個區塊很小、又很少被碰到。
  • solid 壓縮把局部損壞放大。預設情況下很多檔案被壓成一條連續串流,所以 solid 區塊裡任何位置有一個壞位元組,就會毀掉那個區塊裡在它之後的每一個檔案。關掉 solid 模式建立的封存檔,正是用壓縮率換這種局部收斂。
  • 加密的標頭被誤認成損壞。用標頭加密做出來的封存檔,沒有密碼就列不出檔名,所以工具會把它報成讀不了、或什麼都不顯示。這個封存檔完好無缺;它只是拒絕回答。
  • 文字模式傳輸。三十二個位元組的簽章標頭活了下來,所以封存檔會被正確辨識、標頭指標也照樣解得到位置,失敗只會在真正解壓縮那些串流時以 CRC 錯誤的形式出現。

這個格式現在還在用嗎

7z 是主流桌面壓縮工具裡的壓縮率冠軍,在 Windows 上,當 ZIP 太大時大家伸手拿的就是它:LZMA2 配上 solid 區塊,在原始碼樹和文件集合上動輒把 ZIP 的產出砍一半,而 AES-256 加密是內建的、不是外掛上去的。這個格式有公開文件,參考實作也免費,所以 libarchive、p7zip 和多數壓縮工具都讀得懂它。它始終沒能成為的是交換格式。它沒有一等公民級的 Unix 權限或符號連結模型,solid 壓縮讓「只抽一個檔案」有可能貴到離譜,而完全沒有逐檔標頭這件事,讓受損的封存檔比受損的 ZIP 難救太多。在 Unix 上同樣的工作是由 tar.xz 或 tar.zst 完成的,權限模型留在 tar 那一層;而任何要交給不特定收件者打開的東西,安全答案仍然是 ZIP。

在這個站上打開 7-Zip 檔

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

相關格式

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

格式開頭位元組副檔名
ZIP50 4B 03 04.zip
RAR552 61 72 21 1A 07.rar
XZFD 37 7A 58 5A 00.xz
Zstandard28 B5 2F FD.zst

常見問題

檔案的 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 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

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