目次

Compressing a byte array in the ZIP format

バイトarrayを圧縮したり、zipファイルを出力したりするのは、java.util.zipのAPIを用いれば簡単に出来る。
では、バイトarrayを圧縮してzipファイルで出力するのも可能なのか?結論から言えば可能だ。
しかし、あえてファイルではなくバイトアレイを圧縮する必要があるのか。もしファイルを作れない環境であれば1)十分考えられる状況である。

Transfer bytes from a byte array to the ZIP file

private static final int COMPRESS_LEVEL = 9;
 
public long writeZipStream(byte[] input, OutputStream out, String entryName) throws IOException, ZipException{
	// Create a buffer for reading a byte stream
	byte[] buf = new byte[1024];
 
	//Create the ZIP file
	ZipOutputStream output = new ZipOutputStream(out);
 
	//Create a zip entry
	ZipEntry entry = new ZipEntry(entryName);
	entry.setCompressedSize(getCompressedSize(input, entryName));
	entry.setCrc(getCRCValue(input));
	entry.setMethod(ZipEntry.DEFLATED);
 
	//Add ZIP entry to output stream.
	output.putNextEntry(entry);
 
	//Transfer bytes from the file to the ZIP file
        int len=0;
        InputStream in = new ByteArrayInputStream(input);
        while ((len = in.read(buf)) > 0) {
            output.write(buf, 0, len);
        }
 
        // Complete the entry
        output.closeEntry();
        in.close();
 
        //Complete the ZIP file
        output.close();
 
 
        return entry.getCompressedSize();
}//writeZipStream
 
private long getCompressedSize(byte[] input, String entryName) throws IOException {
	ZipEntry entry = new ZipEntry(entryName);
	entry.setMethod(ZipEntry.DEFLATED);
	ZipOutputStream out = new ZipOutputStream(new IdleOutputStream());
	out.setLevel(COMPRESS_LEVEL);
	out.putNextEntry(entry);
	BufferedInputStream in =
		new BufferedInputStream(new ByteArrayInputStream(input));
	int b=0;
	while ((b = in.read()) != -1) {
		out.write(b);
	}
	in.close();
	out.closeEntry();
	out.close();
	return entry.getCompressedSize();
}
 
private long getCRCValue(byte[] input){
    // Compute CRC-32 checksum
    Checksum checksumEngine = new CRC32();
    checksumEngine.update(input, 0, input.length);
    long checksum = checksumEngine.getValue();
 
    // The checksum engine can be reused again for a different byte array by calling reset()
    checksumEngine.reset();
 
    return checksum;
}

Example of compressing a byte array

ここで、肝心なのは圧縮の対象となるファイルのentry名を指定するところだ。
不思議にファイルを何も作っていないのに、まるで作られているように引数で渡している。
実際、“aaa.txt”というentry名がZipEntryのconstructorに引数として渡されている。
なぜかというと、拡張子を含めてentry名を渡さなければ、圧縮対象ファイルの種類が分からない為だ。

byte[] buffer = ((ByteArrayOutputStream)out).toByteArray();
 
response.setContentType("Content-type: application/zip;");
response.addHeader("Content-Disposition", "attachment; filename=xxx.zip");
 
long contentLength = compressor.writeZipStream(buffer, out, "aaa.txt");
res.setHeader("Cache-Control","must-revalidate");
res.setHeader("Content-Length", String.valueOf(contentLength));
//

reference

1)
たとえば、サーバのファイルシステムが分からない場合や権限の為、ファイルの作成ができない場合だ。