goalngのarch/zipをカスタマイズした
golang には標準でライブラリが沢山入っており、例えば zip圧縮/解凍 を行う arch/zip なんてものもある。
もちろん、ソースコードは全て公開されている。 (github)
しかし、このzipライブラリ、使ってく上で2点問題があった。
- zipファイルの編集に向いてない
- Data Descriptor を書き込まない形式に対応していない
この問題を解決するために、はるか昔に arch/zip を fork した物がこちら。
だけど、もろもろ互換性に問題があってサポートしづらかったので、1からforkしなおした。
以下、余談
zipファイルの形式
詳細は こちら を参照で。
単純に書くと、次の形式になる。
+-----------------+ | file header | +-----------------+ | file data | +-----------------+ | data descriptor | *option +-----------------+ ... +-----------------+ | dir header | +-----------------+ ... +-----------------+ | zip end block | +-----------------+
最初に各ファイルに関するブロック (file header
~ data descriptor
) が繰り返され、その次に dir header
がファイルの数だけ繰り返される。
dir header
と書いてあるけど、内容はほぼ file header
と同じである。ディレクトリの情報ブロックでは無いのは注意するところ。
そして、最後にzipファイルそのものの情報を格納する zip end block
が存在する。
なお、これら各ブロックは、名前やコメント、または特別なフィールド (extra) を含んでいるため、全て不定長である。
なんで Data Descriptor が標準なのか
zipは誤解満載で大別すると、以下の2つの形式に分けられる。
- 1パスで読み込めるzipファイル形式
- 1パスで書き込めるzipファイル形式
file header
には通常 file data
のデータサイズが格納されている。
そのため、zipファイルを1パスで読み込むことができる。
しかし、ファイルを作成する場合、ここで問題が発生する。
それは「file header
を書き込む時点で、file data
のサイズ = データの圧縮サイズが決定していないといけない」という問題である。
別に言えば、1パスでzipファイルは書き込めないという問題にもなる。
そのため、1パスでzipファイルを書き込めるように「file header
に書き込めない情報は、file data
の後ろに置こう」としたファイル形式として、data descriptor
が採用できる。
data descriptor
を採用すると、1パスでzipファイルを作成できる (golang だと io.Writer
で十分になる) 。
これは、ネット経由のzip転送など、ランダムアクセスが困難な出力形式に対応できる大きな利点となる。
そのため、golang だと data descriptor
がある形式が標準になっている・・・・・と妄想してる。*1
結局、どっちがいいのか
だいたいのライブラリは data descriptor
があっても正常に解析できるから、data descriptor
がある形式でいいと思う。
どうしても古いライブラリじゃないと駄目、とか、data descriptor
さえ要らないほどファイルサイズを減らしたい、とかの場合のみ、data descriptor
が無い形式を採用すればいい。