◆PROCESSING 逆引きリファレンス
カテゴリー:ファイル操作
ZIP解凍を行うには(zip4j編)
【概要】
PROCESSINGはJavaをベースにした言語ですので、Javaの機能を利用してZIP解凍を行うことが可能です。
ただしJavaの標準機能(標準ライブラリ)では、パスワード付きのZIPファイルを解凍することができません。またAESで圧縮されたZIPファイルも解凍できません。
パスワード付きのZIPファイルを解凍する場合や、より強固な暗号化を施したZIPファイルを解凍する場合に便利なのが zip4jライブラリです。
【詳細】
最新のライブラリを入手する
PROCESSINGでzip4jを使うなら、そのライブラリは Maven Repository からダウンロードするのが便利です。2020年02月現在、Version 2.3.1 が公開されています。
PROCESSINGにzip4jを導入する方法については「ZIP圧縮を行うには(zip4j編)」記事を参照してください。
ZIPファイルを解凍するには、おおまかに以下の手順で作業を行います。
- ZIPファイルを指定して、ZipFileインスタンスを作成
- ZipFileインスタンスからファイルやフォルダを取得
ただし「ZIP解凍を行うには(標準ライブラリ編)」記事で紹介したように、単純に解凍処理を作成するとセキュリティ上問題を引き起こす可能性があります。
特にzip4j 1.3.3 未満を利用する場合は注意が必要です。詳しくはJVN(脆弱性対策情報データベースサイト)を参照してください。
元々ZIPファイルにはセキュリティ上好ましくない部分があるのですが、少しでもリスクを減らしたいのであれば、解凍処理は慎重に作成する必要があります。
以下、順を追って説明します。
ZipFileインスタンスを作成
ZIP解凍するには、ZipFileインスタンスを作成します。
ZipFileインスタンスを作成ZipFile zip = new ZipFile( String zipFileName );
ZipFile zip = new ZipFile( String zipFileName, char[] password );
zip:ZipFileインスタンス
zipFileName:解凍するZIPファイル名
password:パスワード
パスワード付きのZIPファイルを解凍するか否かで、引数が異なります。パスワード付きのZIPファイルを解凍する場合は、第2引数にパスワードを指定します。
例えば以下のような感じです。
1 2 3 |
//パスワード付きZipFileを解凍する ZipFile zip = new ZipFile("C:\\temp\\hoge.zip", "password".toCharArray()); |
パスワード付きのZIPファイルを解凍する場合で、かつZipFileインスタンス作成時にパスワードを指定しない場合は、別途setPassword()メソッドでパスワードを指定する必要があります。
パスワードを指定void zip.setPassword(char[] password);
zip:ZipFileインスタンス
password:パスワード
1 2 3 |
//パスワード付きZipFileを解凍する ZipFile zip = new ZipFile("C:\\temp\\hoge.zip"); zip.setPassword("password".toCharArray()); |
例えば上記のようにして利用します。
パスワードがないZIPファイルを解凍する時にパスワードを指定した場合は、パスワード部分は無視されます。
文字コードを指定する
ZipFileインスタンスに、利用する文字コードの指定を行うことが可能です。日本語のファイルやフォルダー名を含むファイルを解凍する場合は、文字コードを指定しないと文字化けを起こすことがあります。
LinuxやMacの人はUTF-8などを指定すると幸せになれるかもしれませんが、圧縮したファイルの作成元がWindowsの場合は、MS932にしておくのが無難です。
文字コードを指定するvoid zip.setCharset( Charset charset );
zip:ZipFileインスタンス
charset:Charsetクラスの文字コード指定
1 2 3 4 5 6 |
//パスワード付きZipFileを解凍する ZipFile zip = new ZipFile("c:\\temp\\fuga.zip", "password".toCharArray()); //利用する文字コードを指定 zip.setCharset(Charset.forName("MS932")); |
例えば上記のような感じになります。
指定可能な文字コードについては、Javaの公式ドキュメントを参照してください。
ファイルやフォルダを取得
作成されたZipFileインスタンスから、ファイルやフォルダを取り出します。
おおまかに言って3通りの方法があります。
- とにかく全部取り出す
- 指定したファイル名のものだけ取り出す
- 1つ1つ調べながら取り出す
とにかく全部取り出す
最も単純で簡単な方法です。
ZIPファイルから、すべてのファイルとフォルダーを取得して、指定した場所に解凍します。
全て解凍するには、extractAll()メソッドを利用します。
全て解凍するvoid zip.extractAll( String outPath );
zip:ZipFileインスタンス
outPath:解凍する位置
1 2 3 4 5 6 |
//c:¥tempに全て解凍する try{ zip.extractAll("c:\\temp"); } catch( ZipException e ){ e.printStackTrace(); } |
例えば上記のような感じです。
この方法では、指定した位置(例ならc:¥temp)に、ZIPファイルにあるすべてのフォルダーとファイルを解凍します。
フォルダーがない場合は、自動的に作成されます。
この方法は便利ですが、巨大なデータが圧縮されたファイルを扱うときには、十分に注意をしてください。
そうしないと解凍時にCPUやDISKなどのリソースを食いつぶすZIP爆弾攻撃を受ける危険性があります
指定したファイル名のものだけ取り出す
指定したファイル名のものだけを解凍します。この方法は、取り出したいファイル名があらかじめ判っている場合に有効です。
指定したファイル名のものだけ取り出すvoid zip.extractFile( String targetFile, String outPath );
zip:ZipFileインスタンス
targetFile:解凍対象ファイル名
outPath:解凍先のカレントパス位置
ただし指定するファイル名は、圧縮されている階層構造までを含めて指定する必要があります。
例えば、以下のようなfolder1の中にあるfile1.bmpを解凍したい場合は
1 2 3 4 5 6 7 |
ZipFile zip = new ZipFile("c:\\temp\\hoge.zip"); try{ zip.extractFile("folder1\\file1.bmp","c:\\temp" ); } catch( ZipException e ){ e.printStackTrace(); } |
のように指定する必要があります。
解凍先となるカレントパス位置(例ならc:¥temp)が存在しない場合は、自動的に作成されます。また該当パスにフォルダーがない場合(例ならc:¥tempにfolder1が無い場合)も、自動作成されます。
1つ1つ調べながら取り出す
より細かく解凍処理を制御したい(例えば圧縮されているファイルから、png拡張子をもつものだけを解凍したいなどの)場合は、ZIPファイルからFileHeaderを取り出し、調べながら解凍します。
FileHeaderはgetFileHeaders()メソッドで取り出せます。
指定したファイル名のものだけ取り出すList<FileHeader> headerlist = zip.getFileHeaders();
zip:ZipFileインスタンス
headerlist:ファイルヘッダーリスト
取り出したファイルヘッダーを利用すると、対象ファイルやフォルダの様々な情報が取得できます。例えば、以下のようなメソッドが利用可能です。
情報を取得するboolean dirflg = header.isDirectory();
long compsize = header.getCompressedSize();
long uncompsize = header.getUncompressedSize();
String filename = header.getFileName();
header:ファイルヘッダー
dirflg:フォルダーならtrue
compsize:圧縮後サイズ
uncompsize:圧縮前サイズ
filename:ファイル名
例えば以下のようにすると、圧縮ファイルの中にある拡張子がbmpのファイルだけを解凍します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
try{ //圧縮情報を取り出す List<FileHeader> headerList = zip.getFileHeaders(); //拡張子がbmpのファイルだけ解凍する for( FileHeader hd : headerList ){ if( hd.isDirectory() == false ){ if( hd.getFileName().toLowerCase().lastIndexOf(".bmp") > 0){ zip.extractFile( hd, "c:\\temp", hd.getFileName() ); } } } } catch( ZipException e ){ e.printStackTrace(); } |
ただしこの方法も、悪意があるZIPファイルを解凍する場合には危険を伴います。
展開するファイルサイズ(圧縮前後のファイルサイズ)は詐称する事ができるからです。
より確実に解凍するなら、展開対象のファイルサイズは自分で調べながら解凍する工夫が必要でしょう。詳しくは下記サンプルを参照してください。
【関連記事】
サンプルプログラム
ZIPファイルを解凍する例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
/** * PROCESSING 3 zip4j解凍Sample * @auther MSLABO * @version 2020/02 1.0 */ import net.lingala.zip4j.ZipFile; import java.util.List; import java.nio.charset.Charset; import java.io.FileOutputStream; final int TOTAL_SIZE = 10240; //このサイズ(10K)を超えたら異常 final String targetFile = "c:\\temp\\hoge.zip"; final String destDir = "c:\\temp"; void setup(){ //ZipFileを解凍する ZipFile zip = new ZipFile( targetFile ); zip.setCharset(Charset.forName("MS932")); int totalSize = 0; boolean breakFlg = false; //中断FLG try{ //圧縮情報を取り出す List<FileHeader> headerList = zip.getFileHeaders(); //拡張子がbmpのファイルだけ解凍する for( FileHeader hd : headerList ){ if( hd.isDirectory() ){ continue; } if( hd.getFileName().toLowerCase().lastIndexOf(".bmp") <= 0){ continue; } //解凍フォルダーを作成する File outPath = new File(destDir + File.separatorChar + hd.getFileName()); new File( outPath.getParent() ).mkdirs(); // ファイルをディスクに書き出す FileOutputStream out = new FileOutputStream(outPath); ZipInputStream zis = zip.getInputStream( hd ); byte[] buf = new byte[1024]; int size = 0; while ((size = zis.read(buf, 0, 1024)) != -1) { //TOTAL_SIZE以上になったら、そこで中断 totalSize = totalSize + size; if( totalSize >= TOTAL_SIZE){ //上限を超えたので中止 breakFlg = true; break; } //最大1024バイトずつ展開する out.write(buf, 0, size); } out.flush(); out.close(); if(breakFlg){ //MAXオーバーなら、該当ファイルを削除する println( "展開サイズが" + TOTAL_SIZE + "を超えました" ); outPath.delete(); break; } else { println( outPath.getName() + "を解凍しました" ); } } } catch( ZipException e ){ e.printStackTrace(); } catch( IOException e ){ e.printStackTrace(); } } void draw(){ } |
ZIPファイルから拡張子がbmpのファイルを、c:¥tempの下に解凍します。
ただしDISKに書き込んだトータルサイズが10240バイトを超えていた場合は、解凍処理を中断しています。
<出力サンプル>
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。