[zlib.js] JavaScriptでZIP解凍する

JavaScriptでZIP解凍することができるライブラリを紹介します。

zlib.js
https://github.com/imaya/zlib.js/

今回使用したJavaScriptライブラリのバージョンは下記の通りです。

```Markdown:JavaScriptライブラリ
Bootstrap: 3.3.7
jQuery: 3.3.1
zlib.js: 0.3.1
```

# ライブラリの読み込み

`unzip.min.js`を参照します。

```HTML:index.html
<script type="text/javascript" src="../../lib/zlib/unzip.min.js"></script>
```

# AjaxでZIPファイルを取得して、画面上に展開する

下記のようなJSONファイルを用意して、それをZIP圧縮したファイルを作成します。そのZIPファイルをAjaxで取得して、ZIP解凍後、画面上のテキストボックスやラジオボタン、プルダウンに展開します。

```JavaScript:sample/sample001.json
{
    "inputText1": "あいうえお１２３４５",
    "inputRadio1": "1",
    "select1": "3"
}
```

Ajaxで作成したZIPファイルを取得します。

```JavaScript:AjaxでZIPファイル取得する
var url = $('#importFile').val();
var xhr = new XMLHttpRequest
xhr.onload = function () {
    importFile(new Blob([xhr.response]));
}
xhr.open('GET', url, true)
xhr.responseType = 'arraybuffer'
xhr.send();
```

`unzip.getFilenames()`でZIPファイル内のファイルパス一覧を取得します。`unzip.decompress()`でZIP解凍します。JSONファイル内のデータは`utf8ArrayToStr()`でUTF-8の配列から文字列に変換する必要があります。

```JavaScript:ZIP解凍して画面に展開する
var zipReader = new FileReader();
zipReader.onload = function () {
    try {
        var zipArr = new Uint8Array(zipReader.result);
        var unzip = new Zlib.Unzip(zipArr);
        var importFileList = unzip.getFilenames();

        var filePath = 'sample/sample001.json';
        var isExist = false;

        for (var i in importFileList) {
            var importFile = importFileList[i];
            if (importFile === filePath) {
                isExist = true;
            }
        }

        if (!isExist) {
            log('JSON file does not exist. filePath=' + filePath);
            return;
        }

        var jsonBuffer = utf8ArrayToStr(unzip.decompress(filePath));
        var jsonObj = null;

        try {
            jsonObj = JSON.parse(jsonBuffer);
            log('file=\n' + jsonBuffer);
        } catch (e) {
            log('JSON syntax is incorrect.' + e.message);
            return;
        }

        diplayImportFile(jsonObj); // テキストボックスなどの表示を行う
    } catch (e) {
        log(e.message);
    }
}
zipReader.readAsArrayBuffer(file);
```

[デモはこちら](https://yunbow.github.io/sample-zlib-js/01/01/)
[ソースファイルはこちら](https://github.com/yunbow/sample-zlib-js/tree/master/01/01/)

# inputファイルでZIPファイルを指定して、画面上に展開する

`input type="file"`でZIPファイルを指定する方法は下記の通りです。

```JavaScript:index.html
$('#import').on('change', function () {
    var file = $(this).prop('files')[0];
    importFile(file);
});
```

[デモはこちら](https://yunbow.github.io/sample-zlib-js/01/02/)
[ソースファイルはこちら](https://github.com/yunbow/sample-zlib-js/tree/master/01/02/)

# ZIPファイルからinputファイルに指定する

2つのファイル`sample/upload1.json`と`sample/upload2.zip`をZIP圧縮したファイルを作成します。
ZIPファイルを解凍した後、画面上のinputファイルに展開します。

画面上のinputファイルは、セキュリティの問題上、ユーザ操作以外でファイルを読み込ませることができませんので、下記のようにカスタムボタンを作る必要があります。

```HTML:index.html
<input class="hidden inputFile" type="file" id="uploadFile2" />
<input class="btn btn-default inputFileCustom" type="button" id="uploadFile2Custom" value="uploadFile2" />
<span class="fileStatus">not selected.</span>
```

カスタムボタンはユーザ操作にも対応するために下記のような読み込みイベントを実装します。

```JavaScript:カスタムボタンのイベント
$('.inputFileCustom').on('click', function () {
    $(this).parent().find('.inputFile').click();
});

$('.inputFile').on('change', function () {
    var id = $(this).attr('id');
    var file = $(this).prop('files')[0];
    var fileName = file ? file.name : null;
    setInputFile(id, file, fileName);
    $(this).val('');
});
```

`unzip.decompress()`でZIP解凍した後、ファイルをアップロードするためにはBlobに変換します。

```JavaScript:ZIP解凍して画面に展開する
var zipReader = new FileReader();
zipReader.onload = function () {
    try {
        var zipArr = new Uint8Array(zipReader.result);
        var unzip = new Zlib.Unzip(zipArr);
        var importFileList = unzip.getFilenames();

        var uploadFile1Path = 'sample/upload1.json';
        var uploadFile2Path = 'sample/upload2.zip';

        for (var i in importFileList) {
            var importFile = importFileList[i];

            if (importFile === uploadFile1Path) {
                var fileBuffer = unzip.decompress(uploadFile1Path);
                var fileBlob = new Blob([fileBuffer], { type: 'application/octet-stream' });
                setInputFile('uploadFile1', fileBlob, getFileName(uploadFile1Path));
            }

            if (importFile === uploadFile2Path) {
                var fileBuffer = unzip.decompress(uploadFile2Path);
                var fileBlob = new Blob([fileBuffer], { type: 'application/octet-stream' });
                setInputFile('uploadFile2', fileBlob, getFileName(uploadFile2Path));
            }
        }
    } catch (e) {
        log(e.message);
    }
}
zipReader.readAsArrayBuffer(file);
```

[デモはこちら](https://yunbow.github.io/sample-zlib-js/01/04/)
[ソースファイルはこちら](https://github.com/yunbow/sample-zlib-js/tree/master/01/04/)

以上です。

# 関連記事

[[zlib.js] JavaScriptでZIP解凍する](https://qiita.com/yun_bow/items/1b9e86a2efe12432845d)
[[zlib.js] JavaScriptでZIP圧縮する](https://qiita.com/yun_bow/items/4eae0d521cc4237d20d1)