java中常用的压缩与解压

各算法测试结果比较

压缩时间包括对象创建,压缩,解压过程,这里没有移除调对象创建时间,可根据代码多文件大小进行多次测试,这里仅仅是举例

算法名称压缩前文件大小压缩后文件大小压缩时间
deflate1024 * 1077071
gzip1024 * 1077192
bzip21024 * 101029344
lzo1024 * 10102931
lz41024 * 1010324294
snappy1024 * 101024577

抽象接口

/**
 * 数据压缩和解压,提供顶层抽象,执行具体实现
 * <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

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值