目录
各算法测试结果比较
压缩时间包括对象创建,压缩,解压过程,这里没有移除调对象创建时间
,可根据代码多文件大小进行多次测试,这里仅仅是举例
算法名称 | 压缩前文件大小 | 压缩后文件大小 | 压缩时间 |
---|---|---|---|
deflate | 1024 * 10 | 7707 | 1 |
gzip | 1024 * 10 | 7719 | 2 |
bzip2 | 1024 * 10 | 10293 | 44 |
lzo | 1024 * 10 | 10293 | 1 |
lz4 | 1024 * 10 | 10324 | 294 |
snappy | 1024 * 10 | 10245 | 77 |
抽象接口
/**
* 数据压缩和解压,提供顶层抽象,执行具体实现
* <ul>
* <li>deflate</li>
* <li>gzip</li>
* <li>bzip2</li>
* <li>lzo</li>
* <li>lz4</li>
* <li>snappy</li>
* </ul>
*/
public interface Compress {
/**
* 数据压缩
*/
byte[] compress(byte[] data) throws IOException;
/**
* 数据解压
*/
byte[] uncompress(byte[] data) throws IOException;
}
具体的算法实现
deflate
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import priv.dengjl.compress.Compress;
/**
* deflater压缩,基于java jdk
*
* <p>继承关系,基于FilterOutputStream的包装流</p>
* <pre>
* java.lang.Object
* java.io.OutputStream
* java.io.FilterOutputStream
* java.util.zip.DeflaterOutputStream
* </pre>
*
* @author it
*/
public class DeflaterCompress implements Compress {
@Override
public byte[] compress(byte[] data) throws IOException {
// 构建压缩器
Deflater compressor = new Deflater();
compressor.setInput(data);
compressor.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
try {
while (!compressor.finished()) {
int compressLen = compressor.deflate(buffer);
bos.write(buffer, 0, compressLen);
}
} finally {
// 释放资源
compressor.end();
}
return bos.toByteArray();
}
@Override
public byte[] uncompress(byte[] data) throws IOException {
// 构建解压器
Inflater decompressor = new Inflater();
decompressor.setInput(data);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
try {
while (!decompressor.finished()) {
int decompressLen = decompressor.inflate(buffer);
bos.write(buffer, 0, decompressLen);
}
} catch (DataFormatException e) {
throw new RuntimeException(e);
} finally {
// 释放资源
decompressor.end();
}
return bos.toByteArray();
}
}
gzip
/**
* gzip算法
*
* <p>继承关系,基于DeflaterOutputStream的包装</p>
* <pre>
* java.lang.Object
* java.io.OutputStream
* java.io.FilterOutputStream
* java.util.zip.DeflaterOutputStream
* java.util.zip.GZIPOutputStream
* </pre>
*
* @author it
*/
public class GzipCompress implements Compress {
@Override
public byte[] compress(byte[] data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// 通过GZIPOutputStream增值包装流进行压缩
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
gzip.write(data);
}
return out.toByteArray();
}
@Override
public byte[] uncompress(byte[] data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int len = 0;
// 通过GZIPInputStream增值包装流进行解压
try (GZIPInputStream ungzip = new GZIPInputStream(new ByteArrayInputStream(data))){
while ((len = ungzip.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
return out.toByteArray();
}
}
bzip2
/**
* bzip2压缩依赖于apache commons-compress包
*
*/
public class Bzip2Compress implements Compress {
@Override
public byte[] compress(byte[] data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// 通过BZip2CompressorOutputStream增值包装流进行压缩
try (BZip2CompressorOutputStream bcos = new BZip2CompressorOutputStream(out)) {
bcos.write(data);
}
return out.toByteArray();
}
@Override
public byte[] uncompress(byte[] data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int len = 0;
// 通过BZip2CompressorInputStream增值包装流进行解压
try (BZip2CompressorInputStream unbzip = new BZip2CompressorInputStream(new ByteArrayInputStream(data))){
while ((len = unbzip.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
return out.toByteArray();
}
}
lzo
/**
* LZO是致力于解压速度的一种数据压缩算法,LZO是Lempel-Ziv-Oberhumer的缩写。这个算法是无损算法
*
* 依赖于lzo-core包
*
* @author it
*/
public class LzoCompress implements Compress {
@Override
public byte[] compress(byte[] data) throws IOException {
LzoCompressor compressor = LzoLibrary.getInstance().newCompressor(LzoAlgorithm.LZO1X, null);
ByteArrayOutputStream os = new ByteArrayOutputStream();
// 通过LzoOutputStream增值包装流进行压缩
try (LzoOutputStream cs = new LzoOutputStream(os, compressor)) {
cs.write(data);
}
return os.toByteArray();
}
@Override
public byte[] uncompress(byte[] data) throws IOException {
LzoDecompressor decompressor = LzoLibrary.getInstance().newDecompressor(LzoAlgorithm.LZO1X, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int len = 0;
// 通过LzoInputStream增值包装流进行解压
try (LzoInputStream us = new LzoInputStream(new ByteArrayInputStream(data), decompressor)) {
while ((len = us.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
}
return baos.toByteArray();
}
}
lz4
/**
* LZ4是一种无损数据压缩算法,着重于压缩和解压缩速度
*
* 依赖于lz4包
*
* @author it
*/
public class Lz4Compress implements Compress {
@Override
public byte[] compress(byte[] data) throws IOException {
LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 通过LZ4BlockOutputStream增值包装流进行压缩
try (LZ4BlockOutputStream lz4Output = new LZ4BlockOutputStream(baos, 4096, compressor)) {
lz4Output.write(data);
}
return baos.toByteArray();
}
@Override
public byte[] uncompress(byte[] data) throws IOException {
LZ4FastDecompressor decompresser = LZ4Factory.fastestInstance().fastDecompressor();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int len = 0;
// 通过LZ4BlockInputStream增值包装流进行解压
try (LZ4BlockInputStream lzis = new LZ4BlockInputStream(new ByteArrayInputStream(data), decompresser)) {
while ((len = lzis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
}
return baos.toByteArray();
}
}
snappy
**
* Snappy(以前称Zippy)是Google基于LZ77的思路用C++语言编写的快速数据压缩与解压程序库,
* 并在2011年开源。它的目标并非最大压缩率或与其他压缩程序库的兼容性,而是非常高的速度和合理的压缩率
*
* 依赖于snappy-java包
*
* @author it
*/
public class SnappyCompress implements Compress {
@Override
public byte[] compress(byte[] data) throws IOException {
return Snappy.compress(data);
}
@Override
public byte[] uncompress(byte[] data) throws IOException {
return Snappy.uncompress(data);
}
}
测试代码
对象生成辅助类
public enum CompressUtil {
DEFLATER {
Compress compress = new DeflaterCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
BZIP2 {
Compress compress = new LzoCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
GZIP {
Compress compress = new GzipCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
LZ4 {
Compress compress = new Lz4Compress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
LZO {
Compress compress = new LzoCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
SNAPPY {
Compress compress = new SnappyCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
};
public byte[] compress(byte[] data) throws IOException {
throw new AbstractMethodError();
}
public byte[] uncompress(byte[] data) throws IOException {
throw new AbstractMethodError();
}
}
测试类
CompressTest
public class CompressTest {
public static final String allChar = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static String generateString(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(allChar.charAt(random.nextInt(allChar.length())));
}
return sb.toString();
}
public static void main(String[] args) throws IOException {
String data = generateString(1024 * 1000);
// System.out.println("压缩前数据内容:" + data);
byte[] dataBytes = data.getBytes();
System.out.println("压缩前数据大小:" + dataBytes.length);
CompressUtil[] values = CompressUtil.values();
for (CompressUtil compressUtil : values) {
System.out.println("===================: " + compressUtil.name());
long start = System.currentTimeMillis();
byte[] resultBytes = compressUtil.compress(dataBytes);
System.out.println("压缩后数据大小:" + resultBytes.length);
byte[] uncompressBytes = compressUtil.uncompress(resultBytes);
System.out.println("解压后数据大小:" + uncompressBytes.length);
String result = new String(uncompressBytes);
// System.out.println("解压后数据内容:" + result);
System.out.println("压缩时间(ms):" + (System.currentTimeMillis() - start));
System.out.println("===================: " + compressUtil.name());
System.out.println();
}
}
}
测试结果
压缩前数据大小:1024000
===================: DEFLATER
压缩后数据大小:770121
解压后数据大小:1024000
压缩时间(ms):69
===================: DEFLATER
===================: BZIP2
压缩后数据大小:1028208
解压后数据大小:1024000
压缩时间(ms):76
===================: BZIP2
===================: GZIP
压缩后数据大小:770133
解压后数据大小:1024000
压缩时间(ms):74
===================: GZIP
===================: LZ4
压缩后数据大小:1029271
解压后数据大小:1024000
压缩时间(ms):300
===================: LZ4
===================: LZO
压缩后数据大小:1028208
解压后数据大小:1024000
压缩时间(ms):8
===================: LZO
===================: SNAPPY
压缩后数据大小:1024051
解压后数据大小:1024000
压缩时间(ms):74
===================: SNAPPY
公共代码重构
抽象基类AbstractCompress
/**
* 重构gzip、bzip2、lz4、lzo重复代码
*
* @author it
*/
public abstract class AbstractCompress implements Compress {
// 构建模板方法
protected abstract OutputStream createOutputStream(OutputStream output) throws IOException;
protected abstract InputStream createInputStream(InputStream input) throws IOException;
@Override
public byte[] compress(byte[] data) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try (OutputStream cs = createOutputStream(os)) {
cs.write(data);
}
return os.toByteArray();
}
@Override
public byte[] uncompress(byte[] data) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int len = 0;
try (InputStream us = createInputStream(new ByteArrayInputStream(data))) {
while ((len = us.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
}
return baos.toByteArray();
}
}
重构后Bzip2Compress如下
/**
* bzip2压缩依赖于apache commons-compress包
*
*/
public class Bzip2Compress extends AbstractCompress {
@Override
protected OutputStream createOutputStream(OutputStream output) throws IOException {
return new BZip2CompressorOutputStream(output);
}
@Override
protected InputStream createInputStream(InputStream input) throws IOException {
return new BZip2CompressorInputStream(input);
}
}
其他
详见github,这里不再给出
项目地址
详见github项目:https://github.com/dengjili/java-compress