GZIP ファイル形式
gzip で圧縮されたデータ。通常は単一ファイルか tar アーカイブを包みます。
- MIME タイプ
- application/gzip
- 拡張子
- .gz
- カテゴリ
- アーカイブ・圧縮
マジックナンバー(ファイル署名)
| 0x00000000 | 1F8B | ·· | gzip magic |
GZIP 形式について
gzip は DEFLATE で単一のストリームを圧縮する形式で、HTTP 圧縮の基盤であり、どこにでもある .tar.gz の正体でもあります。ファイルは 2 バイトのマジックナンバー 1F 8B で始まります。形式は意図的に小さく作られていて、10 バイトの固定ヘッダ、いくつかの省略可能なフィールド、deflate ストリーム、8 バイトのトレーラだけです。そして意図的にストリーミング可能でもあります。圧縮を始める前に知っておく必要のあるものが何もなく、終わってから戻って直さなければならないものもありません。それがそのまま限界でもあります。ディレクトリもファイル単位の構造も無く、手前を全部展開せずにデータの途中へ到達する手段もありません。
ヘッダーの構造(バイト単位)
| オフセット | 長さ | フィールド | 意味 |
|---|---|---|---|
| 0 | 2 | Magic ID1 ID2 | 1F 8B。どちらのバイトも印字可能な ASCII ではありません。これは意図的で、gzip ストリームがメールゲートウェイや親切心を出すターミナルからテキストに見えてはいけないからです。 |
| 2 | 1 | Compression method (CM) | 8、つまり deflate です。0 から 7 は予約されていて割り当てられたことがないので、実務上ここが 08 以外なら、そのファイルは gzip ではないかヘッダが壊れています。 |
| 3 | 1 | Flags (FLG) | ビット 0 が FTEXT(中身はおそらくテキスト)、ビット 1 が FHCRC(2 バイトのヘッダ CRC が続く)、ビット 2 が FEXTRA、ビット 3 が FNAME(NUL 終端の元ファイル名が続く)、ビット 4 が FCOMMENT。コマンドラインツールで圧縮したファイルは名前を格納するので、通常は 08 と読めます。 |
| 4 | 4 | Modification time (MTIME) | 元ファイルの Unix 秒をリトルエンディアンで、取得できなければ 0 です。同じ入力を 2 回 gzip しても違うバイト列になるのはこれが理由で、再現可能ビルドがこれをゼロにするフラグを渡すのも同じ理由です。 |
| 8 | 1 | Extra flags (XFL) | deflate では 2 が最も遅く最も強い圧縮、4 が最速を意味し、それ以外は 0 です。参考情報でしかなく、これを見て何かをする展開器はありません。 |
| 9 | 1 | Operating system (OS) | 元ファイルが置かれていたファイルシステムです。0 が FAT、3 が Unix、11 が NTFS、255 が不明。どこでビルドされたかが漏れるフィールドで、これも再現可能ビルドが正規化する対象です。 |
| 10 | variable | Optional fields, then the deflate stream | 立っているフラグビットに応じて、決まった順に並びます。拡張フィールド(2 バイトの長さとその分のバイト)、元ファイル名、コメント、ヘッダの CRC-16 です。payload.bin という名前を格納したファイルはオフセット 10 から 21 をそれに使い、deflate は 22 から始まります。 |
| -8 | 4 | CRC-32 of the uncompressed data | リトルエンディアンで、圧縮後ではなく元のバイト列に対して計算します。gzip -t が確認するのはこれで、途中で切れたファイルが決して満たせないのもこれです。 |
| -4 | 4 | ISIZE | 元のサイズを 2^32 で割った余りをリトルエンディアンで。200000 バイトの入力なら末尾は 40 0D 03 00 になります。32 ビットなので 4 ギガバイトを超えると黙って回り込みます。巨大なファイルに対して gzip -l が意味不明な値を返すのはこのためで、確保するメモリのサイズとして決して信用してはいけないのもこのためです。 |
似た形式との見分け方
| 紛らわしい形式 | 見分け方 |
|---|---|
| zlib | 実際に人が引っかかる組み合わせです。どちらも同じ deflate ストリームを包んでいるからです。zlib ストリームのヘッダは 10 バイトではなく 2 バイトで、実務上は 78 01・78 9C・78 DA のいずれか。末尾は CRC-32 ではなく Adler-32 です。マジックナンバーも名前も長さも無いので、.gz にリネームした zlib のかたまりはどこでも開けませんし、zlib のデコーダに gzip を食わせれば即座に失敗します。 |
| raw deflate | RFC 1951 が定める生の deflate には、ヘッダもトレーラもまったくありません。いきなり最初のブロックの 3 ビットから始まります。ZIP のエントリが格納しているのはこれですし、HTTP の Content-Encoding: deflate が曖昧に指していたのもこれです。多くの HTTP クライアントがまず zlib を試し、駄目なら生の deflate にフォールバックするのはそのためです。 |
| TAR | .tar.gz と、普通のファイル 1 つを gzip したものは同じ形式です。違うのは中身だけなので、展開して結果のオフセット 257 を見てください。tar なら最初の 512 バイトのメンバヘッダの中に ustar があります。もっと安上がりな方法として、オフセット 10 の FNAME フィールドがたいてい .tar で終わっていて白状しています。 |
| ZIP | 1F 8B と 50 4B 03 04 で、圧縮という共通の言葉から想像するよりずっと構造が離れています。ZIP は末尾に中央ディレクトリを持ち、他に触れずに 1 エントリを一覧・展開できますが、gzip ストリームは何かに到達するために先頭から読むしかありません。 |
| BZIP2 | BZh に数字が続く形と 1F 8B です。どちらも単一ストリームの Unix 系圧縮ツールで使い方も同じ、ビルドスクリプトの中でほぼ入れ替え可能な名前で呼ばれるので、拡張子はしばしば間違っています。先頭 2 バイトが間違うことはありません。 |
よくある壊れ方
- ダウンロードの途中切れ。8 バイトのトレーラが消えているので、展開器はデコードできる分をすべて出力してから、想定外のファイル終端を報告します。取り出せたバイトはたいてい健全です。問題は、長さもチェックサムも失われた末尾にあったせいで、それを確かめる手段が無いことです。
- deflate ストリーム内のビット反転。出力の長さは正しく、オフセット -8 の CRC-32 が一致しません。gzip -t が存在するのは、まさにこれを名指しするためです。ビットが落ちた場所によっては、チェックサムに到達する前に不正な距離や符号長のエラーで展開そのものが失敗することもあります。
- テキストモード転送。改行変換が圧縮データの中の 0D 0A を 0A に書き換えますが、10 バイトのヘッダは無傷で残るので、ファイルは gzip として認識され、元のファイル名まで報告してから、ストリームの途中で失敗します。
- 複数メンバのアーカイブを 1 つとして読んでしまうケース。gzip ファイルの連結は合法で、準拠した展開器はそれらをつないで全部出力しますが、最初の ISIZE を読んで止める自作パーサは、1 つ目のメンバより後ろを黙って捨てます。並列圧縮ツールが作るのがまさにこの形です。
- ISIZE をサイズとして信用してしまうケース。4 ギガバイトを超えると回り込むので、この値からバッファを確保するプログラムは 4 GiB の倍数ぶんだけ確保量が足りなくなります。これはデータを説明するヘッダフィールドであって約束ではなく、どのチェックサムにも守られていません。
この形式の現在地
gzip は世界でいちばん多く実行されている圧縮形式で、動く気配がありません。どの HTTP スタックも今なおこれをネゴシエートしますし、.tar.gz は Unix でのソース配布の既定の形、ログローテーションが書き出すのもこれ、そしてどの言語も標準ライブラリにデコーダを持っています。読み手が誰か分からないときの安全な答えであり続けているわけです。圧縮率ではとうに負けました。bzip2 も xz も Zstandard もこれを上回りますし、ウェブでは静的なテキストに対して Brotli が上回り、同程度の圧縮率なら速度で Zstandard が上回ります。それでも gzip が第一候補であり続ける理由は、普遍性とストリーミング性の組み合わせです。シークも一時ファイルも入力長の事前知識も要らないので、パイプの中でも、ソケットの中でも、ファームウェアイメージの中でも動きます。逆に、まとまりの中の 1 ファイルだけ取り出したいときには不向きです。索引がありません。それは ZIP の仕事です。
GZIP ファイルをこのサイトで開く
どれもブラウザ内で動きます。ファイルが端末から出ることはありません。
関連する形式
GZIP と混同しやすい形式です。先頭バイトを見比べてください。