◆PROCESSING 逆引きリファレンス
カテゴリー:ファイル操作
ZIP圧縮を行うには(標準ライブラリ編)
【概要】
PROCESSINGはJavaをベースにした言語ですので、Javaの機能を利用してZIP圧縮を行うことが可能です。
ただしJavaの標準機能(標準ライブラリ)では、パスワード付きのZIPファイルを作成することができません。また圧縮方式にZipCrypto(Zip2.0暗号方式)を採用していますが、この圧縮方式には既に脆弱性が発見されています。
おまけにJavaの標準機能(標準ライブラリ)では、圧縮方式にZipCrypto以外を選択することができません!。
そもそもZIP圧縮では、解凍用のパスワードを知らなくても圧縮されたファイル名を見ることができてしまいます。前述の件も考慮すると、セキュリティの確保が重要な場面では、極力ZIPファイルは利用しない事をお勧めします。
それでも手軽に利用できるのがZIPファイルの強みですので、セキュリティよりも利便性を重視する場合には、利用価値があります。
少しでも暗号強度を高めた(暗号化方式にAESを採用した)ZIPファイルを作成する場合や、パスワード付きのZIPファイルを作成したい場合は、標準ライブラリではなく、zip4j ライブラリを利用するのが良いでしょう。
zip4jを使った圧縮方法については「ZIP圧縮を行うには(zip4j編)」を参照してください。
ただしWindowsが標準でサポートしているZIP圧縮解凍機能では、AESで暗号化されたZIPファイルは解凍する事ができない事に注意してください。
詳しくは下記サイト様などが参考となります。
本記事では、Javaの標準ライブラリ(java.util.zip)を用いたZIP圧縮方法について紹介します。
【詳細】
ZIP圧縮を行うには
- 圧縮後のファイル名を元にして、ZipOutputStreamを作成
- ZipOutputStreamに、ZipEntryを追加
- 圧縮する
- ZipEntryとZipOutputStreamをcloseする
という手順で処理を行います。
以下、順番に説明をします。
ZipOutputStreamを作成
ZipOutputStreamは、ZIPファイルの生成(圧縮)を行う基本となるクラスです。圧縮後のファイル名を元にOutputStreamを作成し、それを与えることでインスタンスを作成します。
ZipOutputStream zos = new ZipOutputStream(OutputStream out, Charset charset);
zos:作成したZipOutputStream インスタンス
out:出力対象となる圧縮後のファイルストリーム
charset:エントリ名とコマンドに使用する文字コード
ポイントは文字コードの指定です。
圧縮後のファイルを(日本版)Windowsで利用するなら、日本語名を含むファイルやフォルダを圧縮する場合は、文字コードに「Shift_JIS」または「MS932(windows-31j)」を指定するのが無難です。
なぜなら(日本版)Windowsでは、ZIPファイルに含まれるファイル名やフォルダ名はMS932(windows-31j)である事がデフォルトとなっているからです。
その一方で圧縮後のファイルをMacやLinuxで利用するなら、文字コードに「UTF-8」を指定しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//ZIP出力用オブジェクトを生成 FileOutputStream out = null; String outputFile = "c:\\temp\\hoge.zip"; try { out = new FileOutputStream(outputFile); //Windowsで日本語が文字化けしないように、文字コードにShift-JISを指定 ZipOutputStream zos = new ZipOutputStream( out, Charset.forName("Shift_JIS") ); } catch( FileNotFoundException e){ e.printStackTrace(); } |
例えば上記のようになります。Charsetで指定可能な文字コードについては、公式ドキュメント を参照してください。
ZipEntryを追加
作成したZipOutputStreamに、圧縮対象となるファイルのエントリー情報を追加します。
エントリーはZipEntryクラスのインスタンスとして生成し、ZipOutputStreamのputNextEntry()メソッドで追加します。
ZipEntryを作成ZipEntry entry = new ZipEntry(String name);
entry:エントリー情報
name:エントリー名
.
ZipEntryを追加void zos.putNextEntry(ZipEntry entry);
entry:エントリー情報
zos:ZipOutputStream
その後、エントリーに圧縮する内容(圧縮対象ファイルの中身)を書き込み、ZipOutputStreamのcloseEntry()メソッドで閉じます。
追加するエントリー名は、通常は圧縮対象のファイル名になります。
1 2 3 4 5 6 7 8 9 10 |
//圧縮対象ファイルのエントリーを追加する File targetFile = new File("c:\\temp\\fuga.txt"); ZipEntry entry = new ZipEntry( targetFile.getName() ); try { //エントリーを追加する zos.putNextEntry(entry); } catch( IOException e ){ e.printStackTrace(); } |
例えば上記のような感じです。この場合、「fuga.txt」が圧縮対象ファイルで、そのエントリー名は「fuga.txt」になります。
上記の手順で出来上がるZIPファイルは、以下のようになります。
上記は圧縮したZIPファイルを、解凍ツールで見た様子です。指定したエントリー名(ファイル名)で圧縮されているのがわかりますね。
例えばエントリー名を
1 |
ZipEntry entry = new ZipEntry( "uho" ); |
のようにすると
こうなります。当然ですが、このZIPファイルを解凍すると「uho」というファイルが出来上がることになるので注意してください。
圧縮する
エントリーを追加しただけでは、ファイルは圧縮されません。
エントリーを追加した後で、圧縮対象ファイルの中身を読みだしてZipOutputStreamに書き込む必要があります。
ファイルを全て書き込んだら、追加したZipEntryエントリーをcloseします。また、さらに新しいエントリーを追加する必要がなくなったなら、ZipOutputStreamもcloseします。
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 |
// ZIPファイルに情報を書き込む InputStream is = null; try { //圧縮対象ファイルを読み取り、ZipOutputStreamに出力する is = new BufferedInputStream(new FileInputStream(targetFile)); int len = 0; byte[] buf = new byte[1024]; while ((len = is.read(buf)) != -1) { zos.write(buf, 0, len); } //エントリーとZipOutputStreamを閉じる zos.closeEntry(); zos.close(); } catch( FileNotFoundException e ){ e.printStackTrace(); } catch( IOException e ) { e.printStackTrace(); } finally { try { if (is != null) { is.close(); } } catch( IOException e ) { e.printStackTrace(); } } |
単一のファイル(この場合は hoge.txtファイル)を書き込む例は上記のようになります。上記例で、zosはZipOutputStreamのインスタンス変数です。あとはJavaの標準的なクラスですので、難しいことはないと思います。
これで指定したフォルダに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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
/** * PROCESSING 3 ZIP圧縮Sample * @auther MSLABO * @version 2020/01 1.0 * @see 本プログラムは Tech Blog様 * (https://blog.baseballyama.tokyo/)掲載プログラムを * 流用しています. */ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import java.io.*; import java.nio.charset.Charset; public void setup() { //c:\temp配下の全てのフォルダとファイルを //d:\temp\hoge.zipに圧縮する File zipFile = new File("c:\\temp\\hoge.zip"); File targetDir = new File("c:\\temp"); try { //圧縮する compressDirectory(zipFile, targetDir); } catch( IOException e ){ e.printStackTrace(); } } public void draw() { } /** * 指定したフォルダ配下の全ファイルを取得 * @param parentDir ファイル取得対象フォルダ * @param files ファイル一覧 */ private static void getFiles(File parentDir, ArrayList <File> files) { // ファイル取得対象フォルダ直下のファイル,ディレクトリを走査 for (File f : parentDir.listFiles()) { // ファイルの場合はファイル一覧に追加 if (f.isFile()) { files.add(f); } else if (f.isDirectory()) { // ディレクトリの場合は再帰処理 getFiles(f, files); } } } /** * 指定したフォルダをZIPファイルに圧縮 * @param destination ZIP保存先ファイル * @param dir 圧縮対象のルートフォルダパス * @throws IOException */ private static void compressDirectory(File destination, File dir) throws IOException { // 変数宣言 byte[] buf = new byte[1024]; ZipOutputStream zos = null; InputStream is = null; // ZIP対象フォルダ配下の全ファイルを取得 ArrayList<File> files = new ArrayList<File>(); getFiles(dir, files); try { // ZIP出力オブジェクトを取得(日本語の文字化けに対応するために // 文字コードは Shift-JIS を指定) zos = new ZipOutputStream( new BufferedOutputStream(new FileOutputStream(destination)), Charset.forName("Shift_JIS")); // 全ファイルをZIPに格納 for (File file : files) { // エントリー設定 // 絶対パスから、圧縮対象先頭フォルダまでのパス部分を削除 // c:\temp\hoge\fuga.txt で c:\temp配下を圧縮するなら // hoge\fuga.txtをエントリー名にする ZipEntry entry = new ZipEntry( file.getAbsolutePath().replace( dir.getAbsolutePath() + File.separator, "")); zos.putNextEntry(entry); // ZIPファイルに情報を書き込む is = new BufferedInputStream(new FileInputStream(file)); int len = 0; while ((len = is.read(buf)) != -1) { zos.write(buf, 0, len); } // 入力ストリームとエントリーを閉じる is.close(); is = null; zos.closeEntry(); println( file.getName() + " is compress"); } zos.close(); zos = null; } finally { //ZIP出力ストリームとエントリーを閉じる if (zos != null) { zos.closeEntry(); zos.close(); } if (is != null) { is.close(); } } } |
上記はTech-Blog 様に掲載されていたプログラムを改編して掲載しています。
以下のような状態のフォルダで、c:\temp 配下を圧縮しています。
<出力サンプル>
以下は出来上がった圧縮ファイルの様子です。
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。