じぶんメモ

プログラミングのメモ、日常のメモとか。

JavaでのZipファイル作成

JavaでのZipファイル作成方法を調査した。 一例なので、他の方法もあるかも。
肝心なのは、ZipArchiveOutputStreamのflush()を使用して、1ファイルずつZipに書き込んでいるところ。
flushを使わず、全てのファイルをメモリに格納し、 Zipを生成すると、
OutOfMemoryExceptionが発生する可能性がある。

public String downloadZip() throws Exception {
    //対象年月のFileオブジェクト取得
    File downloadTargetDir = new File("/var/local/testDir/");

    ByteArrayOutputStream zipBAOS = new ByteArrayOutputStream();
    ZipArchiveOutputStream zipArchiveOS = new ZipArchiveOutputStream(zipBAOS);

    // ヘッダー情報設定
    try {
        this.response.setHeader("Content-Transfer-Encoding", "binary");
        this.response.setHeader("Content-Type", "application/zip;charset=UTF-8");
        this.response.setHeader("Content-Disposition", "attachment; filename=\"" + "test.zip" + "\"");
        this.response.setHeader("Cache-Control", "private");
        this.response.setHeader("Pragma", "private");

        // ディレクトリを圧縮
        this.recursiveArchive(outZip, downloadTargetDir);

    } catch ( Exception e ) {
        // ZIP圧縮失敗
        e.printStackTrace();
        throw new Exception(e);
        
    } finally {
        // ZIPエントリクローズ
        try { outZip.closeArchiveEntry(); } catch (Exception e) {}
        try { outZip.close(); } catch (Exception e) {}
        try { zipBAOS.close(); } catch (Exception e) {}
    }
}

/**
 * ディレクトリ圧縮のための再帰処理
 *
 * @param outZip ZipOutputStream
 * @param targetFile File 圧縮したいファイル
 * @param parentFilepath String
 */
private void recursiveArchive(ZipArchiveOutputStream outZip, File targetFile) {
    if ( targetFile.isDirectory() ) {
        File[] files = targetFile.listFiles();
        
        for (File file : files) {
            if ( file.isDirectory() ) {
                recursiveArchive(outZip, file, parentFilepath);
            } else {
                String entryName = file.getName();
                // 圧縮処理
                archive(outZip, file, entryName);
            }
        }
    }
}

/**
 * 圧縮処理
 * @param outZip ZipOutputStream
 * @param targetFile 圧縮したいファイル
 * @param entryName 保存ファイル名
 * @return
 */
private boolean archive(ZipArchiveOutputStream outZip, File targetFile, String entryName) {

    // 圧縮レベル設定
    outZip.setLevel(5);

    try {
        // ZIPエントリ作成
        outZip.putArchiveEntry(new ZipArchiveEntry(entryName));
        // 圧縮ファイル読み込みストリーム取得
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(targetFile));

        // 圧縮ファイルをZIPファイルに出力
        int size = 0;
        //byte buffer[] = new byte[1024]; // 読み込みバッファ
        byte[] bff = new byte[1024];
        while ((size = in.read(bff, 0, bff.length)) != -1) {
            outZip.write(bff, 0, size);
        }
        in.close();
        outZip.closeArchiveEntry();

        try {
            outZip.flush();             
        } catch (Exception e) {
        }            
        
    } catch ( Exception e ) {
        // ZIP圧縮失敗
        return false;
    }
    return true;
}