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

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

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;
    }

测试结果:


image.png


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();
  }

测试结果:


image.png


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();
  }

测试结果:


image.png


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();
  }

测试结果:


image.png


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();
  }

测试结果:


image.png


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();
  }

测试结果:


image.png


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);
  }

测试结果:


image.png


3 性能对比

ENV:JDK:11/CPU:4C/


image.png


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


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


源码地址


上传至Gitee仓库:


Gitee仓库源码


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


相关文章
|
11天前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
30天前
|
存储 Java API
深入剖析Java Map:不只是存储数据,更是设计艺术的体现!
【10月更文挑战第17天】在Java编程中,Map是一种重要的数据结构,用于存储键值对,并展现了设计艺术的精髓。本文深入剖析了Map的设计原理和使用技巧,包括基本概念、设计艺术(如哈希表与红黑树的空间时间权衡)、以及使用技巧(如选择合适的实现类、避免空指针异常等),帮助读者更好地理解和应用Map。
91 3
|
11天前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
29 2
|
11天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
21 2
|
15天前
|
存储 分布式计算 Java
存算分离与计算向数据移动:深度解析与Java实现
【11月更文挑战第10天】随着大数据时代的到来,数据量的激增给传统的数据处理架构带来了巨大的挑战。传统的“存算一体”架构,即计算资源与存储资源紧密耦合,在处理海量数据时逐渐显露出其局限性。为了应对这些挑战,存算分离(Disaggregated Storage and Compute Architecture)和计算向数据移动(Compute Moves to Data)两种架构应运而生,成为大数据处理领域的热门技术。
38 2
|
20天前
|
存储 编解码 负载均衡
数据分片算法
【10月更文挑战第25天】不同的数据分片算法适用于不同的应用场景和数据特点,在实际应用中,需要根据具体的业务需求、数据分布情况、系统性能要求等因素综合考虑,选择合适的数据分片算法,以实现数据的高效存储、查询和处理。
|
20天前
|
存储 缓存 算法
分布式缓存有哪些常用的数据分片算法?
【10月更文挑战第25天】在实际应用中,需要根据具体的业务需求、数据特征以及系统的可扩展性要求等因素综合考虑,选择合适的数据分片算法,以实现分布式缓存的高效运行和数据的合理分布。
|
21天前
|
SQL Java OLAP
java实现“数据平滑升级”
java实现“数据平滑升级”
39 2
|
26天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
23天前
|
SQL Java OLAP
java实现“数据平滑升级”
java实现“数据平滑升级”
13 0
下一篇
无影云桌面