Archive API experimental implement rev.2012.07.28.
Mozilla Hacks よりも先に解説記事を書けました。
概要
10日ほど前に 772434 – Blob support for Zip file contents のパッチが mozilla-central に投入され、DOM File API 経由で取得した zip 形式のアーカイブファイルの取り扱いを行うための API、Archive API が試験的に実装されました。このAPI は最新の Firefox Nightly 17 で試すことができ、このまま何事もなければ 年末にリリースが予定されている Firefox 17 にも載ると予測されます。
今回の Archive API の試験実装は、 今年 7月 17日に Andrea Marchesini によってwhatwg の ML にて提案されたもの( [whatwg] Archive API – proposal )を実装したものになります。
API
今回の試験実装によって、Gecko に以下のインターフェースが実装されました。
- mozilla-central: dom/file/nsIDOMArchiveReader.idl
- mozilla-central: dom/file/nsIDOMArchiveRequest.idl
使い方の流れとしては以下のようになります
- 取得した zip ファイルの
Blob
またはFile
オブジェクトをArchiveReader
コンストラクタに渡してオブジェクトを生成 - 生成した
ArchiveReader
オブジェクトのメソッドを呼び出してArchiveRequest
オブジェクトを取得 - 取得した
ArchiveRequest
に、操作の完了時に呼び出すイベントハンドラを設定
コード的には以下のようになります。
// ArchiveReader のインスタンスを生成 var reader = new ArchiveReader(file); // 格納されたファイル名一覧の取得 var requestFileList = reader.getFilenames(); requestFileList.onsuccess = function (event) { var request = event.target; // this を使っても良い var fileList = request.result; // 配列でファイル名の一覧が返ってくる console.log(fileList); }; // 格納されたファイルの取得 var requestFile = reader.getFile("hoge/sample.txt"); // zipファイル内でのパスを指定 requestFile.onsuccess = function (event) { var request = event.target; var file = request.result; // File オブジェクトが返ってくる console.log("file name" + file.name); console.log("file type" + file.type); console.log("file size" + file.size); };
サンプル
筆者が作成した zip ビューアのサンプルコードへのリンクを以下に記します。
Archive API sample for Firefox Nightly 17 — Gist
テキストファイルのエンコード判別が未実装であったりと、色々と雑な作りとなっています(申し訳ありません)。実行の際には注意をお願いします。
現在の実装における注意点
現在の実装は試験的なものであるため、各所にバグ・考慮漏れと思われる挙動が散見されます。上記のサンプルコードの作成を通じて、筆者が発見したものを以下に挙げます。
パスワードをかけた zip ファイルを渡した場合、ファイルの MIME タイプが application/x-javascript
となる
アーカイブファイル内の構成(格納されているファイルのパス名など)までは読み込むことが可能ですが、ファイル自体の展開は不可能です。
アーカイブされたファイルの名前の文字コードが utf-8 以外の場合、2 byte 文字のファイル名を正しく扱えない
- そのような zip ファイルを開いた場合、
ArchiveReader.getFilenames()
で取得したファイル名の一覧は空文字列の要素の配列になっているように見える(それらの配列の要素は、直接ArchiveReader.getFile()
にパスとして渡した場合にファイルの取得はできるが、文字列として取り扱うことはできない )。 - 同様の zip ファイルを開いた場合、
ArchiveReader.getFile()
にパスを文字列で指定すると、パスが 2 byte 文字の場合はファイルを取得できない
アーカイブされたファイルのサイズが大きい場合(画像・音声・動画など)、ArchiveReader.getFile()
を経由したファイルの展開が途中の状態のまま処理が完了してしまう(ArchiveRequest
に success
イベントが発行される)
取得したファイルのBlob
からwindow.URL.createObjectURL()
すると、ファイルの読み込みが途中のままFileReader.readAsDataURL()
を介した場合、生成された dataURI が中途半端なところで切れている旨の警告が表示されるArchiveRequest.onload()
で回避できるのではないかとおもったが、load
イベントが発行されないためハズレ
780145 – ArchiveReader doesn’t unzip large files が修正され、最新の Nightly では、大きいファイルもちゃんと展開されるようになりました。
まとめ
現在の実装は非常に試験的なものであり、今後、どのような形に API および実装が落ち着いていくかは不透明ではありますが、手軽に zip アーカイブファイルを使用できるようになる可能性が示されたため夢は広がります。Archive API の提案がなされたメールアーカイブでは導入理由として「ゲームの開発のため」と書かれていますが、ゲームに限らず、epubのようなzip形式のコンテナを使用しているフォーマットのビューアの実装や、「複数のリソースファイルを1つに集約して通信をおこなうことによるリクエスト数の軽減」「ファイルを zip で圧縮することによる通信料の軽減」などのテクニックとして取り扱えることが期待できます。
反面、zip アーカイブされたファイルをクライアント上で展開させるという根本的な仕組みから、要求されるメモリ量も大きなものとなりますが、仕様の安定化および実装の普及までの時間がハードウェア性能の向上というかたちで解決してくれるものと前向きに期待しましょう(笑)
saneyuki_s :