ふと、JavaScriptでZIPファイルを扱うのに
良さげなライブラリはないかなと探してみたら、
JSZip と zip.js というのを見つけました。
JSZip は node.js にも対応しているようです。
デモ(1,2,3)の出来が良さげだったので、
zip.js を触ってみることにしました。
使い方は、上述したデモのソースを参照したら大体理解できました。
ダウンロードしたファイルにサンプルソースも付いてるので、
これを参照するのも良さそうです。
デフォルトで web worker に対応しているので、
圧縮や展開を別スレッドで実行して性能向上が期待できそう。
web worker として読み込まれるスクリプトファイル、つまり
z-worker.js, deflate.js, inflate.js の3つの置き場所は
以下のように必要に応じて調整できるようになっています。
zip = {
.
.
.
useWebWorkers : true,
/**
* Directory containing the default worker scripts (z-worker.js, deflate.js, and inflate.js), relative to current base url.
* E.g.: zip.workerScripts = './';
*/
workerScriptsPath : null,
/**
* Advanced option to control which scripts are loaded in the Web worker. If this option is specified, then workerScriptsPath must not be set.
* workerScripts.deflater/workerScripts.inflater should be arrays of urls to scripts for deflater/inflater, respectively.
* Scripts in the array are executed in order, and the first one should be z-worker.js, which is used to start the worker.
* All urls are relative to current base url.
* E.g.:
* zip.workerScripts = {
* deflater: ['z-worker.js', 'deflate.js'],
* inflater: ['z-worker.js', 'inflate.js']
* };
*/
workerScripts : null
};
ただ、日本語のファイル名は文字化けしてしまうので改造してみました。
文字コードを変換するために、encoding.js を使います。
zip.js より前にscriptタグを使って読み込むようにします。
ZIP内部のファイル名エンコーディングは、
ASCII か UTF8 のいずれかになるようです。
SJIS等のマルチバイトはASCIIとして処理されるので文字化けするみたい。
zip.js の一部を以下のように改造して対応しました。
function decodeASCII(str) {
.
.
.
// *MOD* SJIS support
for (i = 0; i < str.length; i++) {
charCode = str.charCodeAt(i);
if (charCode >= 128 && charCode <= 255)
out += extendedASCII[charCode - 128];
else
out += String.fromCharCode(charCode);
}
return out;
}
// *MOD* SJIS support
function getString(bytes) {
return String.fromCharCode.apply( undefined, Encoding.convert( bytes, 'UNICODE', 'SJIS' ) );
}
ところで、
zip.js には ZIPファイルを FileSystem のように扱える
zip-fs.js というのが同梱されています。
zip-fs.js では zip.js の FileWriter という機能を使っているのですが、
なぜか zip.fs にはその機能が実装されていません。
デモ3においてフォルダの内容をZIPとしてexportするとエラーとなります。
なぜ実装されていないのかは不明。
FileSystem API を使ってどうにかするしかないのか?
zip-fs.js を使わなくても圧縮や展開はできるのでとりあえず問題はなさそう。