数据压缩算法的介绍-Java实现-对比

本文介绍了Zlib、Gzip、Bzip2等多种压缩算法的原理及Java实现,并通过模拟测试比较了它们的性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 前言

在RPC通信数据的传输场景下,当通信报文数据传输较大时,会对数据包进行压缩传输,根据不同传输场景,常用的压缩算法有Zlib、Gzip、Bzip2、Deflater、Lz4、Lzo、Snappy算法等。以下将包括算法的介绍、Java实现代码以及各算法间的模拟性能对比。

2 压缩方案

  • Zlib

bzip2是Julian Seward开发并按照自由软件/开源软件协议发布的数据压缩算法及程序。对于压缩和解压缩,没有数据长度的限制,bzip2比传统的gzip的压缩效率更高,但是它的压缩速度较慢。

核心代码:

@Override
    public byte[] compress(byte[] data) throws IOException {
        byte[] output;

        Deflater compresser = new Deflater();

        compresser.reset();
        compresser.setInput(data);
        compresser.finish();
        ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
        try {
            byte[] buf = new byte[1024];
            while (!compresser.finished()) {
                int i = compresser.deflate(buf);
                bos.write(buf, 0, i);
            }
            output = bos.toByteArray();
        } catch (Exception e) {
            output = data;
            e.printStackTrace();
        } finally {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        compresser.end();
        return output;
    }

    @Override
    public byte[] uncompress(byte[] data) throws IOException {
        byte[] output;

        Inflater decompresser = new Inflater();
        decompresser.reset();
        decompresser.setInput(data);

        ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);
        try {
            byte[] buf = new byte[1024];
            while (!decompresser.finished()) {
                int i = decompresser.inflate(buf);
                o.write(buf, 0, i);
            }
            output = o.toByteArray();
        } catch (Exception e) {
            output = data;
            e.printStackTrace();
        } finally {
            try {
                o.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        decompresser.end();
        return output;
    }

测试结果:

图片

  • Gzip

gzip的实现算法还是deflate,只是在deflate格式上增加了文件头和文件尾,同样jdk也对gzip提供了支持,分别是GZIPOutputStream和GZIPInputStream类,同样可以发现GZIPOutputStream是继承于DeflaterOutputStream的,GZIPInputStream继承于InflaterInputStream,并且可以在源码中发现writeHeader和writeTrailer方法。

核心代码:

@Override
	public byte[] compress(byte[] data) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		GZIPOutputStream gzip;

		try {
			gzip = new GZIPOutputStream(out);
			gzip.write(data);
			gzip.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return out.toByteArray();
	}

	@Override
	public byte[] uncompress(byte[] data) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ByteArrayInputStream in = new ByteArrayInputStream(data);

		try {
			GZIPInputStream ungzip = new GZIPInputStream(in);
			byte[] buffer = new byte[2048];
			int n;
			while ((n = ungzip.read(buffer)) >= 0) {
				out.write(buffer, 0, n);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return out.toByteArray();
	}

测试结果:

图片

  • Bzip2

bzip2是Julian Seward开发并按照自由软件/开源软件协议发布的数据压缩算法及程序。Seward在1996年7月第一次公开发布了bzip2 0.15版,在随后几年中这个压缩工具稳定性得到改善并且日渐流行,Seward在2000年晚些时候发布了1.0版。bzip2比传统的gzip的压缩效率更高,但是它的压缩速度较慢。

核心代码:

@Override
	public byte[] compress(byte[] data) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		BZip2CompressorOutputStream bcos = new BZip2CompressorOutputStream(out);
		bcos.write(data);
		bcos.close();

		return out.toByteArray();
	}

	@Override
	public byte[] uncompress(byte[] data) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ByteArrayInputStream in = new ByteArrayInputStream(data);

		try {
			@SuppressWarnings("resource")
			BZip2CompressorInputStream ungzip = new BZip2CompressorInputStream(in);
			byte[] buffer = new byte[2048];
			int n;
			while ((n = ungzip.read(buffer)) >= 0) {
				out.write(buffer, 0, n);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return out.toByteArray();
	}

测试结果:

图片

  • Deflater

DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法,DEFLATE压缩与解压的源代码可以在自由、通用的压缩库zlib上找到,zlib官网:http://www.zlib.net/ jdk中对zlib压缩库提供了支持,压缩类Deflater和解压类Inflater,Deflater和Inflater都提供了native方法。

核心代码:

@Override
	public byte[] compress(byte[] data) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		Deflater compressor = new Deflater(1);
		
		try {
			compressor.setInput(data);
			compressor.finish();
			final byte[] buf = new byte[2048];
			while (!compressor.finished()) {
				int count = compressor.deflate(buf);
				bos.write(buf, 0, count);
			}
		} finally {
			compressor.end();
		}
		
		return bos.toByteArray();
	}

	@Override
	public byte[] uncompress(byte[] data) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		Inflater decompressor = new Inflater();
		
		try {
			decompressor.setInput(data);
			final byte[] buf = new byte[2048];
			while (!decompressor.finished()) {
				int count = decompressor.inflate(buf);
				bos.write(buf, 0, count);
			}
		} catch (DataFormatException e) {
			e.printStackTrace();
		} finally {
			decompressor.end();
		}
		
		return bos.toByteArray();
	}

测试结果:

图片

  • Lz4

LZ4是一种无损数据压缩算法,着重于压缩和解压缩速度。

核心代码:

@Override
	public byte[] compress(byte[] data) throws IOException {
		LZ4Factory factory = LZ4Factory.fastestInstance();
		ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
		LZ4Compressor compressor = factory.fastCompressor();
		LZ4BlockOutputStream compressedOutput = new LZ4BlockOutputStream(byteOutput, 2048, compressor);
		compressedOutput.write(data);
		compressedOutput.close();
		
		return byteOutput.toByteArray();
	}

	@Override
	public byte[] uncompress(byte[] data) throws IOException {
		LZ4Factory factory = LZ4Factory.fastestInstance();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		LZ4FastDecompressor decompresser = factory.fastDecompressor();
		LZ4BlockInputStream lzis = new LZ4BlockInputStream(new ByteArrayInputStream(data), decompresser);
		
		int count;
		byte[] buffer = new byte[2048];
		while ((count = lzis.read(buffer)) != -1) {
			baos.write(buffer, 0, count);
		}
		lzis.close();
		
		return baos.toByteArray();
	}

测试结果:

图片

  • Lzo

LZO是致力于解压速度的一种数据压缩算法,LZO是Lempel-Ziv-Oberhumer的缩写,这个算法是无损算法。

核心代码:

@Override
	public byte[] compress(byte[] data) throws IOException {
		LzoCompressor compressor = LzoLibrary.getInstance().newCompressor(LzoAlgorithm.LZO1X, null);
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		LzoOutputStream cs = new LzoOutputStream(os, compressor);
		cs.write(data);
		cs.close();

		return os.toByteArray();
	}

	@Override
	public byte[] uncompress(byte[] data) throws IOException {
		LzoDecompressor decompressor = LzoLibrary.getInstance().newDecompressor(LzoAlgorithm.LZO1X, null);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ByteArrayInputStream is = new ByteArrayInputStream(data);
		@SuppressWarnings("resource")
		LzoInputStream us = new LzoInputStream(is, decompressor);
		
		int count;
		byte[] buffer = new byte[2048];
		while ((count = us.read(buffer)) != -1) {
			baos.write(buffer, 0, count);
		}
		
		return baos.toByteArray();
	}

测试结果:

图片

  • Snappy

Snappy(以前称Zippy)是Google基于LZ77的思路用C++语言编写的快速数据压缩与解压程序库,并在2011年开源。它的目标并非最大压缩率或与其他压缩程序库的兼容性,而是非常高的速度和合理的压缩率。

核心代码:

@Override
	public byte[] compress(byte[] data) throws IOException {
		return Snappy.compress(data);
	}

	@Override
	public byte[] uncompress(byte[] data) throws IOException {
		return Snappy.uncompress(data);
	}

测试结果:

图片

3 性能对比

ENV:JDK:11/CPU:4C/

图片

不同大小文件压缩效率及质量有差异,性能对比仅供参考;

Compress Rate(%) = Size Before(byte) / Size After(byte) * 100%

源码地址

上传至Gitee仓库:

Gitee仓库源码

https://gitee.com/javanoteany/compress.git

点赞评论+关注你是最棒的人!

Java实现压缩与解压缩ZIP   import java.io.BufferedInputStream;   import java.io.BufferedOutputStream;   import java.io.File;   import java.io.FileInputStream;   import java.io.FileOutputStream;   import java.util.zip.ZipEntry;   import java.util.zip.ZipOutputStream;   public class Zip {   static final int BUFFER = 2048;   public static void main(String argv[]) {   try {   BufferedInputStream origin = null;   FileOutputStream dest = new FileOutputStream("E:\\test\\myfiles.zip");   ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(   dest));   byte data[] = new byte[BUFFER];   File f = new File("e:\\test\\a\\");   File files[] = f.listFiles();   for (int i = 0; i < files.length; i++) {   FileInputStream fi = new FileInputStream(files[i]);   origin = new BufferedInputStream(fi, BUFFER);   ZipEntry entry = new ZipEntry(files[i].getName());   out.putNextEntry(entry);   int count;   while ((count = origin.read(data, 0, BUFFER)) != -1) {   out.write(data, 0, count);   }   origin.close();   }   out.close();   } catch (Exception e) {   e.printStackTrace();   }   }   }   解压缩的   import java.io.BufferedInputStream;   import java.io.BufferedOutputStream;   import java.io.File;   import java.io.FileOutputStream;   import java.util.Enumeration;   import java.util.zip.ZipEntry;   import java.util.zip.ZipFile;   public class UnZip {   static final int BUFFER = 2048;   public static void main(String argv[]) {   try {   String fileName = "E:\\test\\myfiles.zip";   String filePath = "E:\\test\\";   ZipFile zipFile = new ZipFile(fileName);   Enumeration emu = zipFile.entries();   int i=0;   while(emu.hasMoreElements()){   ZipEntry entry = (ZipEntry)emu.nextElement();   //会把目录作为一个file读出一次,所以只建立目录就可以,之下的文件还会被迭代到。   if (entry.isDirectory())   {   new File(filePath + entry.getName()).mkdirs();   continue;   }   BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));   File file = new File(filePath + entry.getName());   //加入这个的原因是zipfile读取文件是随机读取的,这就造成可能先读取一个文件   //而这个文件所在的目录还没有出现过,所以要建出目录来。   File parent = file.getParentFile();   if(parent != null && (!parent.exists())){   parent.mkdirs();   }   FileOutputStream fos = new FileOutputStream(file);   BufferedOutputStream bos = new BufferedOutputStream(fos,BUFFER);   int count;   byte data[] = new byte[BUFFER];   while ((count = bis.read(data, 0, BUFFER)) != -1)   {   bos.write(data, 0, count);   }   bos.flush();   bos.close();   bis.close();   }   zipFile.close();   } catch (Exception e) {   e.printStackTrace();   }   }   }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值