DeflateComparison.java
package gov.usgs.earthquake.distribution;
import gov.usgs.earthquake.product.FileContent;
import gov.usgs.earthquake.product.Product;
import gov.usgs.earthquake.product.ProductId;
import gov.usgs.earthquake.product.io.BinaryProductHandler;
import gov.usgs.earthquake.product.io.ObjectProductSource;
import gov.usgs.util.StreamUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Date;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
public class DeflateComparison {
/**
* Deflate an input stream.
*
* @param level
* deflate level.
* @param in
* input stream to deflate.
* @return output length in bytes.
* @throws IOException if IO error occurs
*/
public long deflateStream(final int level, final InputStream in)
throws IOException {
CountingOutputStream cos = new CountingOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(cos, new Deflater(
level));
StreamUtils.transferStream(in, new StreamUtils.UnclosableOutputStream(
dos));
dos.finish();
dos.close();
return cos.getTotalBytes();
}
/**
* Transfer an input stream.
*
* @param in
* input stream to transfer.
* @return output length in bytes.
* @throws IOException if IO error occurs
*/
public long transferStream(final InputStream in) throws IOException {
CountingOutputStream cos = new CountingOutputStream();
StreamUtils.transferStream(in, cos);
return cos.getTotalBytes();
}
/**
* Test different compression levels and speeds for a file.
*
* Reads file into memory to avoid disk io overhead.
*
* @param file
* file to test.
* @throws IllegalArgumentException if illegal arg
* @throws IOException if IO error occurs
*/
public void testFile(final File file) throws IllegalArgumentException,
IOException {
// read into memory to avoid disk io overhead
byte[] fileContent = StreamUtils.readStream(StreamUtils
.getInputStream(file));
testByteArray(file.getCanonicalPath(), fileContent);
}
/**
* Test different compression levels and speeds for a byte array.
*
* @param name
* given name
* @param content
* content to test.
* @throws IllegalArgumentException if illegal arg
* @throws IOException if IO error occurs
*/
public void testByteArray(final String name, final byte[] content)
throws IOException {
Date start;
long totalBytes = content.length;
System.err.println(name + ", length = " + totalBytes + " bytes");
System.err.println("no compression");
start = new Date();
long noCompression = transferStream(new ByteArrayInputStream(content));
long noCompressionTime = new Date().getTime() - start.getTime();
formatResult(totalBytes, noCompression, noCompressionTime);
System.err.println("default compression (-1)");
start = new Date();
long deflateDefault = deflateStream(Deflater.DEFAULT_COMPRESSION,
new ByteArrayInputStream(content));
long deflateDefaultTime = new Date().getTime() - start.getTime();
formatResult(totalBytes, deflateDefault, deflateDefaultTime);
System.err.println("best speed (1)");
start = new Date();
long deflateBestSpeed = deflateStream(Deflater.BEST_SPEED,
new ByteArrayInputStream(content));
long deflateBestSpeedTime = new Date().getTime() - start.getTime();
formatResult(totalBytes, deflateBestSpeed, deflateBestSpeedTime);
System.err.println("best compression (9)");
start = new Date();
long deflateBestCompression = deflateStream(Deflater.BEST_COMPRESSION,
new ByteArrayInputStream(content));
long deflateBestCompressionTime = new Date().getTime()
- start.getTime();
formatResult(totalBytes, deflateBestCompression,
deflateBestCompressionTime);
}
/**
* For calculating for properly formatting the results
*
* @param totalBytes totalBytes
* @param transferredBytes Bytes transferred
* @param elapsedTime total elapsed time
*/
protected void formatResult(final long totalBytes,
final long transferredBytes, final long elapsedTime) {
long savedBytes = totalBytes - transferredBytes;
System.err.printf("\t%.3fs, %.1f%% reduction (%d fewer bytes)%n",
elapsedTime / 1000.0,
100 * (savedBytes / ((double) totalBytes)), savedBytes);
}
/**
* An output stream that counts how many bytes are written, and otherwise
* ignores output.
*/
private static class CountingOutputStream extends OutputStream {
// number of bytes output
private long totalBytes = 0L;
public long getTotalBytes() {
return totalBytes;
}
@Override
public void write(byte[] b) {
totalBytes += b.length;
}
@Override
public void write(byte[] b, int offset, int length) {
totalBytes += length;
}
@Override
public void write(int arg0) throws IOException {
totalBytes++;
}
}
/**
* A main method for accessing tests using custom files.
*
* @param args
* a list of files or directorys to include in compression
* comparison.
* @throws Exception if error occurs
*/
public static void main(final String[] args) throws Exception {
if (args.length == 0) {
System.err.println("Usage: DeflateComparison FILE [FILE ...]");
System.err
.println("where FILE is a file or directory to include in comparison");
System.exit(1);
}
Product product = new Product(new ProductId("test", "test", "test"));
try {
product.setTrackerURL(new URL("http://localhost/tracker"));
} catch (Exception e) {
// ignore
}
// treat all arguments as files or directories to be added as content
for (String arg : args) {
File file = new File(arg);
if (!file.exists()) {
System.err.println(file.getCanonicalPath() + " does not exist");
System.exit(1);
}
if (file.isDirectory()) {
product.getContents().putAll(
FileContent.getDirectoryContents(file));
} else {
product.getContents()
.put(file.getName(), new FileContent(file));
}
}
// convert product to byte array in binary format
System.err.println("Reading files into memory");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new ObjectProductSource(product)
.streamTo(new BinaryProductHandler(baos));
new DeflateComparison().testByteArray("product contents",
baos.toByteArray());
}
}