クライアントサイドでzipファイルの展開後のファイルサイズの合計を出す要件があり、その対応をメモしておく。
ちなみに用語として展開を表す言葉は「解凍」や「伸張」等様々だが、本投稿では「展開」で統一しておく。#個人的にはどれでもよいが
##要件
要件は以下の通り。
・画面でzipファイルの展開後のファイルサイズを測り、サーバにリクエストしたい
・画面には「input type="file"」のファイル入力欄がある
・ライブラリは「zlib.js」を使用する
・可能であれば展開せずにファイルサイズのみ知りたい
##zlib.jsとは?
簡単にzlib.jsについて説明。
zlibというC言語で作成されたオープンソースのライブラリを使用したjavascript向けのライブラリ。
詳しくはこちらを参照のこと。(https://github.com/imaya/zlib.js/)
#zlibはgzipを開発した方が作成したらしく、圧縮・展開を取り扱う場合に広く利用されている。javaの圧縮・展開もzlibを使用しているらしい。
##展開後のファイルサイズを取得するコード
コードは以下の通り。
<script src="vendors/zlib/unzip.min.js"></script>
~中略~
var file = document.getElementById("file").files[0]; // fileがファイル入力欄
var reader = new FileReader();
reader.readAsArrayBuffer(file);
var unzip = new Zlib.Unzip(new Uint8Array(reader.result));
unzip.getFilenames(); // 呼び出すことでファイル情報のオブジェクトの配列が生成される
var fileInfoArray = unzip.i; // ファイル情報のオブジェクトの配列
var decompressedFileSize = fileInfoArray.reduce((sum, file) => sum + file.J, 0); // Jに展開後のファイルサイズが格納されている
##説明
注意すべき点はUnzipコンストラクタの引数。FileReaderで読み込んだ結果はArrayBufferなのでUint8Arrayに正している。
#自分はこれをしないでエラーが出てハマってしまった。。。
もう一点、getFilenames()を呼び出しているところ。これを呼び出すことでファイル情報のオブジェクトが生成されるらしい。
ファイル情報のオブジェクトの配列の変数名や展開後のファイルサイズの変数名を見てわかる通り、一般に利用されることが想定されていないものなので、利用は自己責任で。
ちなみに、ディレクトリを含む場合、ディレクトリの要素の展開後のファイルサイズは必ず0になっているため、ディレクトリか否かを特段気にせず合計を求められる。
これで展開することなく全ファイルの合計が求められる。
#展開は、unzip.decompress("filename")を呼び出すことで展開後のUint8Arrayが取得できる。この処理を行わずに展開後のファイルサイズを求めているため、展開することなく合計が求められていると判断している(一応元ソースも見たがdecompressを呼び出さない限り展開はされていないはず)