プログラム悪戦苦闘日記

はてなダイアリーからの移行(遺物)

ZIP圧縮をしてみる - part1 zip書き込み -

 JavaでZIPファイルを扱うには java.util.zip パッケージを使う。このパッケージはJDK1.1からあるにもかかわらず、ZIP圧縮を説明しているサイトは非常に少ないと思う。まぁ、javadoc読めば分かる、ということなのか。とにかく今回はzipの書き込みをやってみたいと思う。プログラムは下記の通りで、結果は画像*1のようになる。

import java.util.zip.*;
import java.io.*;

public class Main {
    public static void main(String[] args) 
    throws Exception {
        String str = init(); // ZIP保存したい文字列
        
        ZipOutputStream zip = new ZipOutputStream(new FileOutputStream("hoge.zip")); // (1)
        zip.setLevel(9); // 最高の圧縮レベル
        
        zip.putNextEntry(new ZipEntry("piyo1.txt")); // (2)
        zip.write(str.getBytes(), 0, str.length()*2); // (3)
        zip.closeEntry(); // (3)
        
        zip.putNextEntry(new ZipEntry("piyo2.txt"));
        zip.write(str.getBytes(), 0, str.length()*2);
        zip.closeEntry();
        
        zip.putNextEntry(new ZipEntry("hoge/piyo3.txt"));
        zip.write(str.getBytes(), 0, str.length()*2);
        zip.closeEntry();
        
        zip.close(); // (5)
    }
    
    static String init() {
        StringBuilder buf = new StringBuilder(2048);
        for(int i=1; i<=1024; ++i)
            buf.append("ほげ");
        return buf.toString();
    }
}

 ZIP圧縮ファイルを作るのに必要なクラスは、ZipOutputStreamとZipEntryの2つだけだ。ZipOutputStreamクラスが、ZIPアーカイブを全体を出力するクラスで、これが任意のOutputStreamに結び付けられる。ファイルとして出力するときはFileOutputStreamに結びつければ良い (1)。
 ZipEntryが、ZIPアーカイブに入れる「ファイル」や「ディレクトリ」を表す。ZipEntryをnewして、このインスタンスをZipOutputStream#putNextEntry()すれば加えられる (2)。実際にデータを書きこむのは、ZipEntryにではなくZipOutputStrea.write(byte[], int, int)である (3)。このメソッドで現在のZipEntryに書き込む。基本的にZipEntryは読み込みに使うようなので、いくらこのクラスのメソッドを調べてもデータは書き込めない(エントリー情報を設定するsetterメソッドはいくつかある)。書き込むメソッドは、先のwriteしかないから、byte配列しか書き込めない。
 ZipEntryに必要なデータをすべて書き込んだら、ZipOutputStream#closeEntry()でZipEntryを閉じる (3)。続けて別のエントリーを書き込みたいときは、(1)〜(3)を繰り返せばよい。
 また、ディレクトリを書き込みたいときは、(4)にある通り hoge/piyo.txt のように、エントリー名を /(スラッシュ)で区切って行けばよい。
 最後にZipOutputStream#close()で、Zipストリーム自体を閉じる (5)。
 
 やっぱり、あまり難しくなかった。これとjava.io系のディレクトリ捜査やファイル属性取得を組み合わせれば、ディレクトリを丸ごとZIP圧縮ができるだろう。

*1:画像がぼやけて見にくいので撤去しました