はじめに
Web上でのファイルのやりとりとして使われるファイル形式に、Zip ファイルがあります。
普段何気なく使用しているこの Zip ファイルですが、その内部構造を理解している方は少ないと思います。
ここでは、この Zip ファイルを扱うライブラリの説明に入る前に、その内部の構造について、説明していきます。
というのも、Zip ファイルの内部構造を理解した方が、その圧縮・展開を行うライブラリについて理解しやすいからです。
それでは、Zip ファイルとは、そもそもなにものなのかから順にたどっていきたいと思います。
Zip ファイルとは
Zip ファイルの形式は、Phil Katz(フィル・カッツ)氏が率いた米国のソフトウェア会社 PKWARE によって開発され、1989年に登場しました。
当時は ARC というアーカイブ形式が広く使われており、Phil Katz 氏も当初 ARC 互換の PKARC というソフトを作成していました。
しかし、このソフトを巡って、ARC を開発した Systems Enhancement Associates(SEA)との間で法的な問題が発生したことを受け、新しいアーカイブ形式を開発することになり、それが Zip へとつながっていきました。
Zip ファイル仕様 は 1989 年に PKZIP とともに登場しました。その際、Zip ファイルの仕様そのものが広く公開されたため、他社でも扱えるようになり、広く普及していくことになりました。
PKWARE は現在も Zip ファイルの仕様を APPNOTE として公開・更新しており、これが長年にわたる互換性の基盤になっています。
現在の Zip は、
- Central Directory
- End of Central Directory
- Local File Header
- CRC
- 圧縮方式
- ファイル属性
- ZIP64
- Unicode対応
- 暗号化
など、かなり巨大な仕様になっています。
しかし、ZIPの基本的な構造は 1989 年から脈々と受け継がれています。
さらに後から、
- 1993 年 → ZIP 2.0で DEFLATE が導入
- 2001 年 → ZIP 4.5で ZIP64 が導入され、4GB 超・ 65535 ファイル超に対応
というように拡張されていきました。
👉 1989 年に生まれた Zip は、基本構造を維持したまま、35 年以上にわたって拡張され続けています。
私もそうですが、その恩絵にあずかっている方も多いと思います。この場をお借りして、開発者、また関係者の方々に深くお礼を申し上げたいと思います。
さて、話は戻りますが、Zip ファイルというと、圧縮ファイルを思い浮かべる方も多いと思います。しかし、厳密には、Zip ファイルは「圧縮ファイル」ではなく、「圧縮機能を持ったアーカイブ形式」です。
意外とここを誤解している方は多いと思います。
以降では、なぜ、Zip ファイルが「圧縮機能を持ったアーカイブ形式」と呼ばれるのかについて掘り下げていきたいと思います。
Zip ファイルの内部構造
基本的な Zip ファイルは下記のような内部構造となっています。
┌───────────────────────────┐
│ File1 │
│ ┌───────────────────────┐ │
│ │ Local File Header │ │
│ ├───────────────────────┤ │
│ │ 圧縮データ │ │
│ └───────────────────────┘ │
├───────────────────────────┤
│ File2 │
│ ┌───────────────────────┐ │
│ │ Local File Header │ │
│ ├───────────────────────┤ │
│ │ 圧縮データ │ │
│ └───────────────────────┘ │
├───────────────────────────┤
│ : │
│ : │
├───────────────────────────┤
│ Central Directory │
├───────────────────────────┤
│ End of Central Directory │
└───────────────────────────┘
このように、複数のファイルを1つのファイルに束ねた構造になっており、各ファイルの中身は、圧縮または無圧縮のデータとして格納されます。
ここで、注意が必要なのが、圧縮データは必ずしも、圧縮される必要はないということです。つまり、それが、Zip ファイルが「圧縮機能を持ったアーカイブ形式」といわれる所以です。
◇ Local File Header
Local File Headerには、
- ファイル名
- 圧縮方式
- CRC
- 圧縮サイズ
- 元サイズ
など、そのファイルに関する情報が格納されています。そして、その直後に、圧縮データが続きます。
つまり、格納されているファイルの数だけ
Local File Header
圧縮データ
Local File Header
圧縮データ
Local File Header
圧縮データ
:
という並びになっています。
※ 巨大なファイルをストリーミング処理により Zip ファイルに格納する場合などは、Local File Header の CRC やサイズなどを Local File Header に記録せず、圧縮データの後ろに Data Descriptor を設け、実際の値をそこに格納する場合があります。
┌──────────────────────┐
│ Local File Header │
│ CRC / サイズ:未記録 │
├──────────────────────┤
│ 圧縮データ │
├──────────────────────┤
│ Data Descriptor │
│ CRC = 確定値 │
│ Size = 確定値 │
└──────────────────────┘
◇ Central Directory
Central Directory は、Zip ファイルの「目次」になります。
例えば
sample/test.txt sample/image/photo.jpg
が入っているなら、Central Directory には、
sample/test.txt
更新日時
CRC32
圧縮サイズ
元サイズ
Local File Header の位置
sample/image/photo.jpg
更新日時
CRC32
圧縮サイズ
元サイズ
Local File Header の位置
のような一覧が入っています。
なぜ「目次」が必要となるのでしょうか?
例えば、
1000個のファイルが格納されている Zip ファイルの中から、あるファイルを検索するとします。
ここで、もし Central Directory が無いと、
Local File Header
圧縮データ
Local File Header
圧縮データ
Local File Header
圧縮データ
:
を最初から全部読んで、「あ、このファイルがある」と探すしかありません。
しかし Central Directory があると、これを読むだけで、そのファイルの存在や、存在位置まで特定できます。
👉 展開ソフトは、まず Central Directory だけを読むことで、Zip ファイルの構成を知ることができるようになるのです。
◇ End of Central Directory (EOCD)
これは、Zip ファイルの終わりを示す情報です。
中には
Central Directory の開始位置
Central Directory のサイズ
ファイル数
コメント長
Zip コメント
などが入っています。
つまり、このZIPは
・ファイル数 ○○ 個 ・目次はここから始まる ・目次のサイズは ○○ バイト
という案内板の役割を示します。
ここで、察しのいい方は、疑問に思われると思います。End of Central Directory ( EOCD ) の最後には、コメント長とZip コメント、つまり、可変長のコメント領域が存在します。
ということは、EOCD 全体が、可変長であるということです。
では、どうやって、EOCD の先頭をみつけるのでしょうか?
実は、通常のZIP(ZIP64ではない)のEOCDは次のようになっています。
| 項目 | サイズ |
|---|---|
シグネチャ (0x06054b50) |
4バイト |
| このディスク番号 | 2バイト |
| Central Directory開始ディスク番号 | 2バイト |
| このディスク上のエントリ数 | 2バイト |
| 全エントリ数 | 2バイト |
| Central Directoryのサイズ | 4バイト |
| Central Directoryの開始位置 | 4バイト |
| ZIPコメント長 | 2バイト |
| ZIPコメント | 0~65535バイト |
このように、EOCD の先頭には、シグネチャ (0x06054b50) が識別子として書き込まれています。ZIPファイルの末尾から、EOCDが存在し得る範囲を検索し、シグネチャ 0x06054b50 を探すことで、EOCD の先頭をみつけることができます。
実は、Local File Header や Central Directory にも、シグネチャが存在します。
PK 03 04 ← Local File Header
...
PK 03 04 ← Local File Header
...
PK 01 02 ← Central Directory Entry
PK 01 02 ← Central Directory Entry
...
PK 05 06 ← End of Central Directory
※ 余談ですが、Zip ファイルを 16 進エディタで開くと、この構造がそのまま見えてきます。
◇ ZIP64 仕様の拡張領域
通常のZIPでは、ファイル数やファイルサイズ、Central Directoryのサイズ・位置などを格納する一部のフィールドに、16bitまたは32bitの制限があります。
- ファイル数 16bit ( 65535 )
- サイズ 32bit ( 4GB )
- オフセット 32bit ( 4GB )
ZIP64 仕様では、Zip ファイル形式の 16bit や 32bit という制限を、ファイルサイズ・圧縮サイズ・ファイル数・Central Directoryの位置やサイズなど、必要な箇所について 64bit へ拡張する仕組みが追加されました。
これらの追加は、互換性を維持するために、文字通り従来の仕様に追加される形で策定されています。
具体的には、従来の Zip ファイル形式に下記のような変更点があります。
1. Local File Header の拡張
従来の Local File Header に加え、Extra Field が追加されています。
〇 通常ZIPLocal Header ┌─────────────────────────────────────────┐ │ サイズ : 32bit │ └─────────────────────────────────────────┘
〇 ZIP64
Local Header ┌─────────────────────────────────────────┐ │ サイズ : 0xFFFFFFFF │ ← 「ZIP64を見て」 ├─────────────────────────────────────────┤ │ ZIP64 Extended Information Extra Field │ │ └ サイズ : 64bit │ └─────────────────────────────────────────┘
※ ZIP64では、従来の32bitフィールドでは表現できない値について、そのフィールドに 0xFFFFFFFF などの特別な値を設定し、実際の64bit値を ZIP64 Extended Information Extra Field から取得します。
ZIP64 Extended Information Extra Field には、
Uncompressed Size 8 bytes
Compressed Size 8 bytes
Relative Header Offset 8 bytes
Disk Start Number 4 bytes
といった情報が必要に応じて格納されます。
2. ZIP64 対応の Central Directory の追加
ZIP64 に対応した専用の End of Central Directory と Locator が 従来の Central Directory と End of Central Directory の間に追加されています。
│ : │
│ : │
├────────────────────────────────┤
│ Central Directory │
├────────────────────────────────┤
│ ZIP64 End of Central Directory │
├────────────────────────────────┤
│ ZIP64 Locator │
├────────────────────────────────┤
│ End of Central Directory │
└────────────────────────────────┘
□ ZIP64 End of Central Directory
通常のEOCDでは表現できないZIP64用の情報を、より大きなフィールドで格納するために追加されたレコードです。
概念的には、
┌─────────────────────────────┐
│ Signature │ 4
├─────────────────────────────┤
│ Record Size │ 8
├─────────────────────────────┤
│ Version Made By │ 2
│ Version Needed │ 2
│ Disk Number │ 4
│ Central Directory Disk │ 4
│ Entries on this disk │ 8
│ Total entries │ 8
│ Central Directory Size │ 8
│ Central Directory Offset │ 8
└─────────────────────────────┘
のようになっています。
□ ZIP64 Locator
これは、ZIP64 End of Central Diretory ( EOCD ) がどこにあるかを指し示すものです。
┌──────────────────────────────┐
│ Signature │ 4
├──────────────────────────────┤
│ ZIP64 EOCDのディスク番号 │ 4
├──────────────────────────────┤
│ ZIP64 EOCDのファイル位置 │ 8
├──────────────────────────────┤
│ ディスク総数 │ 4
└──────────────────────────────┘
という構造です。
ZIP64 の仕様のすごいところは、従来の構造を置き換えるのではなく、従来の Zip ファイル構造を維持することで、既存の Zip ファイルとの互換性をできるだけ保ちながら、ZIP64 対応ソフトでは大容量の情報を扱えるようにしています。
※ ZIP64 は現在、多くの圧縮・展開ソフトで利用されています。ただし、ライブラリやソフトによって対応範囲が異なる場合があるため、大容量の Zip ファイルを扱う際には対応状況の確認が必要です。
(つづく)