Java实现数据压缩所有方式性能测试

这篇具有很好参考价值的文章主要介绍了Java实现数据压缩所有方式性能测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


1 BZip方式

Java实现数据压缩所有方式性能测试
ZIP文件格式是一种数据压缩和文档储存的文件格式,原名Deflate,发明者为菲尔·卡茨(Phil Katz),他于1989年1月公布了该格式的资料。ZIP通常使用后缀名“.zip”,它的MIME格式为application/zip。当前,ZIP格式属于几种主流的压缩格式之一,其竞争者包括RAR格式以及开放源码的7z格式。从性能上比较,RAR及7z格式较ZIP格式压缩率较高,而7-Zip由于提供了免费的压缩工具而逐渐在更多的领域得到应用。Microsoft从Windows ME操作系统开始内置对zip格式的支持,即使用户的计算机上没有安装解压缩软件,也能打开和制作zip格式的压缩文件,OS X和流行的Linux操作系统也对zip格式提供了类似的支持。因此如果在网络上传播和分发文件,zip格式往往是最常用的选择。

1.1 引入依赖

        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.10.6</version>
        </dependency>

1.2 BZip工具类代码

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.apache.tools.bzip2.CBZip2InputStream;
import org.apache.tools.bzip2.CBZip2OutputStream;

public class BZip2Util {

    private static final int BUFFER_SIZE = 8192;

    public static byte[] compress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (CBZip2OutputStream bzip2 = new CBZip2OutputStream(bos)) {
            bzip2.write(bytes);
            bzip2.finish();
            return bos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("BZip2 compress error", e);
        }
    }

    public static byte[] decompress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        try (CBZip2InputStream bzip2 = new CBZip2InputStream(bis)) {
            byte[] buffer = new byte[BUFFER_SIZE];
            int n;
            while ((n = bzip2.read(buffer)) > -1) {
                out.write(buffer, 0, n);
            }
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("BZip2 decompress error", e);
        }
    }
}

1.3 BZip2工具类代码

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.apache.tools.bzip2.CBZip2InputStream;
import org.apache.tools.bzip2.CBZip2OutputStream;

public class BZip2Util {

    private static final int BUFFER_SIZE = 8192;

    public static byte[] compress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (CBZip2OutputStream bzip2 = new CBZip2OutputStream(bos)) {
            bzip2.write(bytes);
            bzip2.finish();
            return bos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("BZip2 compress error", e);
        }
    }

    public static byte[] decompress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        try (CBZip2InputStream bzip2 = new CBZip2InputStream(bis)) {
            byte[] buffer = new byte[BUFFER_SIZE];
            int n;
            while ((n = bzip2.read(buffer)) > -1) {
                out.write(buffer, 0, n);
            }
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("BZip2 decompress error", e);
        }
    }
}

2 Deflater方式

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

public class DeflaterUtil {

    private DeflaterUtil() {

    }

    private static final int BUFFER_SIZE = 8192;

    public static byte[] compress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        int lenght = 0;
        Deflater deflater = new Deflater();
        deflater.setInput(bytes);
        deflater.finish();
        byte[] outputBytes = new byte[BUFFER_SIZE];
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            while (!deflater.finished()) {
                lenght = deflater.deflate(outputBytes);
                bos.write(outputBytes, 0, lenght);
            }
            deflater.end();
            return bos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("Deflater compress error", e);
        }
    }

    public static byte[] decompress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        int length = 0;
        Inflater inflater = new Inflater();
        inflater.setInput(bytes);
        byte[] outputBytes = new byte[BUFFER_SIZE];
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();) {
            while (!inflater.finished()) {
                length = inflater.inflate(outputBytes);
                if (length == 0) {
                    break;
                }
                bos.write(outputBytes, 0, length);
            }
            inflater.end();
            return bos.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Deflater decompress error", e);
        }
    }

}

3 Gzip方式

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class GzipUtil {

    private GzipUtil() {

    }

    private static final int BUFFER_SIZE = 8192;

    public static byte[] compress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
            gzip.write(bytes);
            gzip.flush();
            gzip.finish();
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("gzip compress error", e);
        }
    }

    public static byte[] decompress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try (GZIPInputStream gunzip = new GZIPInputStream(new ByteArrayInputStream(bytes))) {
            byte[] buffer = new byte[BUFFER_SIZE];
            int n;
            while ((n = gunzip.read(buffer)) > -1) {
                out.write(buffer, 0, n);
            }
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("gzip decompress error", e);
        }
    }
}

4 Lz4方式

4.1 简介

Lz4压缩算法是由Yann Collet在2011年设计实现的,lz4属于lz77系列的压缩算法。lz77严格意义上来说不是一种算法,而是一种编码理论,它只定义了原理,并没有定义如何实现。基于lz77理论衍生的算法除lz4以外,还有lzss、lzb、lzh等。

lz4是目前基于综合来看效率最高的压缩算法,更加侧重于压缩解压缩速度,压缩比并不突出,本质上就是时间换空间。

对于github上给出的lz4性能介绍:每核压缩速度大于500MB/s,多核CPU可叠加;它所提供的解码器也是极其快速的,每核可达GB/s量级。

4.2 算法思想

lz77编码思想:它是一种基于字典的算法,它将长字符串(也可以称为匹配项或者短语)编码成短小的标记,用小标记代替字典中的短语,也就是说,它通过用小的标记来代替数据中多次重复出现的长字符串来达到数据压缩的目的。其处理的符号不一定是文本字符,也可以是其他任意大小的符号。

短语字典维护:lz77使用的是一个前向缓冲区和一个滑动窗口。它首先将数据载入到前向缓冲区,形成一批短语,再由滑动窗口滑动时,变成字典的一部分。

4.3 算法实现

4.3.1 lz4数据格式

lz4实现了两种格式,分别是lz4_block_format和lz4_frame_format。

lz4_frame_format用于特殊场景,如file压缩、pipe压缩和流式压缩;这里主要介绍lz4_block_format(一般场景使用格式)

压缩块有多个序列组成,一个序列是由一组字面量(非压缩字节),后跟一个匹配副本。每个序列以token开始,字面量和匹配副本的长度是有token以及offset决定的。

literals指没有重复、首次出现的字节流,即不可压缩的部分

literals length指不可压缩部分的长度

match length指重复项(可以压缩的部分)长度

下图为单个序列的数据格式,一个完整的lz4压缩块是由多个序列组成的。

Java实现数据压缩所有方式性能测试

2、lz4压缩过程

lz4遵循上面说到的lz77思想理论,通过滑动窗口、hash表、数据编码等操作实现数据压缩。压缩过程以至少4字节为扫描窗口查找匹配,每次移动1字节进行扫描,遇到重复的就进行压缩。

举个例子:给出一个字符串: abcde_fghabcde_ghxxahcde,描述出此字符串的压缩过程

ps:我们按照6字节扫描窗口,每次1字节来进行扫描

Java实现数据压缩所有方式性能测试

  1. 假设lz4的滑动窗口大小为6字节,扫描窗口为1字节;
  2. lz4开始扫描,首先对0-5位置做hash运算,hash表中无该值,所以存入hash表;
  3. 向后扫描,开始计算1-6位置hash值,hash表中依然无此值,所以继续将hash值存入hash表;
  4. 扫描过程依次类推,直到图中例子,在计算9-15位置的hash值时,发现hash表中已经存在,则进行压缩,偏移量offset值置为9,重复长度为6,该值存入token值的低4位中;
  5. 匹配压缩项后开始尝试扩大匹配,当窗口扫描到10-16时,发现并没有匹配到,则将此值存入hash表;如果发现hash表中有值,如果符合匹配条件(例如10-15符合1-6)则扩大匹配项,重复长度设为7,调整相应的token值
  6. 这样滑动窗口扫描完所有的字符串之后,结束操作

最终,这样压缩过程就结束了,得到这样一个字节串[-110, 97, 98, 99, 100, 101, 95, 102, 103, 104, 9, 0, -112, 103, 104, 120, 120, 97, 104, 99, 100, 101]。大家可能在看到这段内容可能有些懵逼,我在解压过程解释一下。

3、lz4解压过程

lz4压缩串: [-110, 97, 98, 99, 100, 101, 95, 102, 103, 104, 9, 0, -112, 103, 104, 120, 120, 97, 104, 99, 100, 101]

二进制是字符串经过utf-8编码后的值

下图是对上面压缩串的解释:

Java实现数据压缩所有方式性能测试

这里简单记录下解压的过程:

  1. 当lz4解压从0开始遍历时,先判断token值(-110),-110转换为计算机二进制为10010010,高四位1001代表字面量长度为9,低四位0010代表重复项匹配的长度2+4(minimum repeated bytes)
  2. 向后遍历9位,得到长度为9的字符串(abcde_fgh),偏移量为9,从当前位置向前移动9位则是重复位起始位置,低四位说明重复项长度为6字节,则继续生成长度为6的字符串(abcde_)
  3. 此时生成(abcde_fghabcde_),接着开始判断下一sequence token起始位,最终生成abcde_fghabcde_ghxxahcde(压缩前的字符串)

4.4 Lz4-Java

lz4/lz4-java是由Rei Odaira等人写的一套使用lz4压缩的Java类库。

4.4.1 简介

该类库提供了对两种压缩方法的访问,他们都能生成有效的lz4流:

  1. 快速扫描(lz4)
    1. 内存占用少(16KB)
    2. 非常快
    3. 合理的压缩比(取决于输入的冗余度)
  2. 高压缩(lz4hc)
    1. 内存占用中等(256KB)
    2. 相当慢(比lz4慢10倍)
    3. 良好的压缩比(取决于输入的大小和冗余度)
  3. 这两种压缩算法产生的流使用相同的压缩格式,解压缩速度非常快,可以由相同的解压缩实例解压缩

4.4.2 类库

该类库提供了几个关键类,这里简单介绍一下

LZ4Factory

Lz4 API的入口点,该类有3个实例

  1. 一个native实例,它是与原始LZ4 C实现的JNI绑定
  2. 一个safe Java实例,它是原始C库的纯Java端口(Java 官方编写的API)
  3. 一个unsafe Java实例,它是使用非官方sun.misc.Unsafe API的Java端口(Unsafe类可用来直接访问系统内存资源并进行自主管理,其在提升Java运行效率,增强Java语言底层操作能力方面起到很大的作用,Unsafe可认为是Java中留下的后门,提供了一些低层次操作,如直接内存访问、线程调度等)

只有safe Java实例才能保证在JVM上工作,因此建议使用fastestInstance()或fastestJavaInstance()来拉取LZ4Factory实例。

LZ4Compressor

压缩器有两种,一种是fastCompressor,也就是lz4简介中说的快速扫描压缩器;另一种是highCompressor,是实现高压缩率压缩器(lz4hc)。

LZ4Decompressor

lz4-java提供了两个解压器:LZ4FastDecompressor;LZ4SafeDecompressor

两者不同点在于:LZ4FastDecompressor在解压缩时是已知源字符串长度,而LZ4SafeDecompressor在解压缩时是已知压缩字段的长度

使用

上面说到的两个压缩器和两个解压缩器,在压缩和解压缩的时候,是可以互换的,比如说FastCompressor可以和LZ4SafeDecompressor搭配使用这样,因为两种压缩算法生成的流格式是一样的,无论用哪个解压缩器都能解压。

在说完上面基本的类之后,再来看下lz4-Java类库给我们提供流式传输类:LZ4BlockOutputStream(输出流-编码)、LZ4BlockInputStream(输入流-解码)

下面这段代码是使用示例:

package com.oldlu.compress.utils;

import net.jpountz.lz4.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

public class Lz4Utils {
    private static final int ARRAY_SIZE = 4096;
    private static LZ4Factory factory = LZ4Factory.fastestInstance();
    private static LZ4Compressor compressor = factory.fastCompressor();
    private static LZ4FastDecompressor decompressor = factory.fastDecompressor();
    private static LZ4SafeDecompressor safeDecompressor = factory.safeDecompressor();

    public static byte[] compress(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            LZ4BlockOutputStream lz4BlockOutputStream = new LZ4BlockOutputStream(outputStream, ARRAY_SIZE, compressor);
            lz4BlockOutputStream.write(bytes);
            lz4BlockOutputStream.finish();
            return outputStream.toByteArray();
        } catch (Exception e) {
            System.err.println("Lz4压缩失败");
        }
        return null;
    }

    public static byte[] uncompress(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream(ARRAY_SIZE);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
            LZ4BlockInputStream decompressedInputStream = new LZ4BlockInputStream(inputStream, decompressor);
            int count;
            byte[] buffer = new byte[ARRAY_SIZE];
            while ((count = decompressedInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, count);
            }
            return outputStream.toByteArray();
        } catch (Exception e) {
            System.err.println("lz4解压缩失败");
        }
        return null;
    }

    public static void main(String[] args) {
        byte[] bytes = "abcde_fghabcde_ghxxahcde".getBytes(StandardCharsets.UTF_8);

        byte[] compress = compress(bytes);

        byte[] decompress = uncompress(compress);
    }
}

5 SevenZ方式

5.1 引入依赖

        <dependency>
            <groupId>org.tukaani</groupId>
            <artifactId>xz</artifactId>
            <version>1.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-compress</artifactId>
            <version>1.19</version>
        </dependency>

5.2 工具类代码

import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class SevenZUtil {

    private static final int BUFFER_SIZE = 8192;

    public static byte[] compress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel();
        try (SevenZOutputFile z7z = new SevenZOutputFile(channel)) {
            SevenZArchiveEntry entry = new SevenZArchiveEntry();
            entry.setName("sevenZip");
            entry.setSize(bytes.length);
            z7z.putArchiveEntry(entry);
            z7z.write(bytes);
            z7z.closeArchiveEntry();
            z7z.finish();
            return channel.array();
        } catch (IOException e) {
            throw new RuntimeException("SevenZ compress error", e);
        }
    }

    public static byte[] decompress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(bytes);
        try (SevenZFile sevenZFile = new SevenZFile(channel)) {
            byte[] buffer = new byte[BUFFER_SIZE];
            while (sevenZFile.getNextEntry() != null) {
                int n;
                while ((n = sevenZFile.read(buffer)) > -1) {
                    out.write(buffer, 0, n);
                }
            }
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("SevenZ decompress error", e);
        }
    }

 
}

6 Zip方式

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;


public class ZipUtil {

    private static final int BUFFER_SIZE = 8192;

    public static byte[] compress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try (ZipOutputStream zip = new ZipOutputStream(out)) {
            ZipEntry entry = new ZipEntry("zip");
            entry.setSize(bytes.length);
            zip.putNextEntry(entry);
            zip.write(bytes);
            zip.closeEntry();
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("Zip compress error", e);
        }
    }

    public static byte[] decompress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try (ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(bytes))) {
            byte[] buffer = new byte[BUFFER_SIZE];
            while (zip.getNextEntry() != null) {
                int n;
                while ((n = zip.read(buffer)) > -1) {
                    out.write(buffer, 0, n);
                }
            }
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("Zip decompress error", e);
        }
    }
}

7 性能对比

我们可以使用它来和其他压缩类进行一个性能对比

测试源代码:

package com.oldlu.compress.test;

import com.oldlu.compress.domain.User;
import com.oldlu.compress.service.UserService;
import com.oldlu.compress.utils.*;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.TimeUnit;



@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class PerformanceTest {
    /**
     * 用来序列化的用户对象
     */
    @State(Scope.Benchmark)
    public static class CommonState {
        User user;
        byte[] originBytes;
        byte[] lz4CompressBytes;
        byte[] snappyCompressBytes;
        byte[] gzipCompressBytes;
        byte[] bzipCompressBytes;
        byte[] deflateCompressBytes;

        @Setup(Level.Trial)
        public void prepare() {
            UserService userService = new UserService();
            user = userService.get();
            originBytes = ProtostuffUtils.serialize(user);
            lz4CompressBytes = Lz4Utils.compress(originBytes);
            snappyCompressBytes = SnappyUtils.compress(originBytes);
            gzipCompressBytes = GzipUtils.compress(originBytes);
            bzipCompressBytes = Bzip2Utils.compress(originBytes);
            deflateCompressBytes = DeflateUtils.compress(originBytes);
        }
    }

    /**
     * Lz4压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] lz4Compress(CommonState commonState) {
        return Lz4Utils.compress(commonState.originBytes);
    }

    /**
     * lz4解压缩
     *
     * @param commonState
     */
    @Benchmark
    public byte[] lz4Uncompress(CommonState commonState) {
        return Lz4Utils.uncompress(commonState.lz4CompressBytes);
    }

    /**
     * snappy压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] snappyCompress(CommonState commonState) {
        return SnappyUtils.compress(commonState.originBytes);
    }


    /**
     * snappy解压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] snappyUncompress(CommonState commonState) {
        return SnappyUtils.uncompress(commonState.snappyCompressBytes);
    }


    /**
     * Gzip压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] gzipCompress(CommonState commonState) {
        return GzipUtils.compress(commonState.originBytes);
    }

    /**
     * Gzip解压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] gzipUncompress(CommonState commonState) {
        return GzipUtils.uncompress(commonState.gzipCompressBytes);
    }

    /**
     * bzip2压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] bzip2Compress(CommonState commonState) {
        return Bzip2Utils.compress(commonState.originBytes);
    }

    /**
     * bzip2压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] bzip2Uncompress(CommonState commonState) {
        return Bzip2Utils.uncompress(commonState.bzipCompressBytes);
    }

    /**
     * bzip2压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] deflateCompress(CommonState commonState) {
        return DeflateUtils.compress(commonState.originBytes);
    }

    /**
     * bzip2压缩
     *
     * @param commonState
     * @return
     */
    @Benchmark
    public byte[] deflateUncompress(CommonState commonState) {
        return DeflateUtils.uncompress(commonState.deflateCompressBytes);
    }


    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(PerformanceTest.class.getSimpleName())
                .forks(1)
                .threads(1)
                .warmupIterations(10)
                .measurementIterations(10)
                .result("PerformanceTest.json")
                .resultFormat(ResultFormatType.JSON).build();
        new Runner(opt).run();
    }
}

性能测试图:

附上lz4官网给出的性能测试图和自己测试的性能图,有些差异,有可能对于压缩数据的不同导致的差异。

官网给的:

Java实现数据压缩所有方式性能测试

手工测:

Java实现数据压缩所有方式性能测试

在公司对于特征内容的压缩,观察lz4和snappy的对比,看上去lz4和snappy的压缩和解压缩的性能差不多,但lz4更稳定些,尖刺场景少。由于设计公司内部内容,就不粘图了。

7.1 压缩率对比

在压缩率上,按照从高到低是:bzip2 > Deflate > Gzip > lz4 > snappy

package com.oldlu.compress.demo;

import com.alibaba.fastjson.JSONObject;
import com.oldlu.compress.domain.User;
import com.oldlu.compress.service.UserService;
import com.oldlu.compress.utils.*;

import java.nio.charset.StandardCharsets;


public class CompressDemo {
    public static void main(String[] args) {
        User user = new UserService().get();
        // json序列化
        byte[] origin_json = JSONObject.toJSONBytes(user);
        System.out.println("原始json字节数: " + origin_json.length);
        // pb序列化
        byte[] origin = ProtostuffUtils.serialize(user);
        System.out.println("原始pb字节数: " + origin.length);

        testGzip(origin, user);
        testSnappy(origin, user);
        testLz4(origin, user);
        testBzip2(origin, user);
        testDeflate(origin, user);

    }

    private static void test(){
        System.out.println("--------------------");
        String str = getString();
        byte[] source = str.getBytes(StandardCharsets.UTF_8);
        byte[] compress = Lz4Utils.compress(source);
        // 将compress转为字符串
        System.out.println(translateString(compress));
        System.out.println();
        System.out.println("--------------------");
        String str2 = getString2();
        byte[] source2 = str2.getBytes(StandardCharsets.UTF_8);
        byte[] compress2 = Lz4Utils.compress(source2);
        byte[] uncompress = Lz4Utils.uncompress(compress2);
        System.out.println();
    }

    private static String translateString(byte[] bytes) {
        char[] chars = new char[bytes.length];
        for (int i = 0; i < chars.length; i++) {
            chars[i] = (char) bytes[i];
        }
        String str = new String(chars);
        return str;
    }

    private static String getString() {
        return "fghabcde_bcdefgh_abcdefghxxxxxxx";
    }

    private static String getString2() {
        return "abcde_fghabcde_ghxxahcde";
    }


    private static void testGzip(byte[] origin, User user) {
        System.out.println("---------------GZIP压缩---------------");
        // Gzip压缩
        byte[] gzipCompress = GzipUtils.compress(origin);
        System.out.println("Gzip压缩: " + gzipCompress.length);
        byte[] gzipUncompress = GzipUtils.uncompress(gzipCompress);
        System.out.println("Gzip解压缩: " + gzipUncompress.length);
        User deUser = ProtostuffUtils.deserialize(gzipUncompress, User.class);
        System.out.println("对象是否相等: " + user.equals(deUser));
    }

    private static void testSnappy(byte[] origin, User user) {
        System.out.println("---------------Snappy压缩---------------");
        // Snappy压缩
        byte[] snappyCompress = SnappyUtils.compress(origin);
        System.out.println("Snappy压缩: " + snappyCompress.length);
        byte[] snappyUncompress = SnappyUtils.uncompress(snappyCompress);
        System.out.println("Snappy解压缩: " + snappyUncompress.length);
        User deUser = ProtostuffUtils.deserialize(snappyUncompress, User.class);
        System.out.println("对象是否相等: " + user.equals(deUser));
    }

    private static void testLz4(byte[] origin, User user) {
        System.out.println("---------------Lz4压缩---------------");
        // Lz4压缩
        byte[] Lz4Compress = Lz4Utils.compress(origin);
        System.out.println("Lz4压缩: " + Lz4Compress.length);
        byte[] Lz4Uncompress = Lz4Utils.uncompress(Lz4Compress);
        System.out.println("Lz4解压缩: " + Lz4Uncompress.length);
        User deUser = ProtostuffUtils.deserialize(Lz4Uncompress, User.class);
        System.out.println("对象是否相等: " + user.equals(deUser));
    }

    private static void testBzip2(byte[] origin, User user) {
        System.out.println("---------------bzip2压缩---------------");
        // bzip2压缩
        byte[] bzip2Compress = Bzip2Utils.compress(origin);
        System.out.println("bzip2压缩: " + bzip2Compress.length);
        byte[] bzip2Uncompress = Bzip2Utils.uncompress(bzip2Compress);
        System.out.println("bzip2解压缩: " + bzip2Uncompress.length);
        User deUser = ProtostuffUtils.deserialize(bzip2Uncompress, User.class);
        System.out.println("对象是否相等: " + user.equals(deUser));
    }

    private static void testDeflate(byte[] origin, User user) {
        System.out.println("---------------Deflate压缩---------------");
        // Deflate压缩
        byte[] deflateCompress = DeflateUtils.compress(origin);
        System.out.println("Deflate压缩: " + deflateCompress.length);
        byte[] deflateUncompress = DeflateUtils.uncompress(deflateCompress);
        System.out.println("Deflate解压缩: " + deflateUncompress.length);
        User deUser = ProtostuffUtils.deserialize(deflateUncompress, User.class);
        System.out.println("对象是否相等: " + user.equals(deUser));
    }
}
原始json字节数: 5351
原始pb字节数: 3850
---------------GZIP压缩---------------
Gzip压缩: 2170
Gzip解压缩: 3850
对象是否相等: true
---------------Snappy压缩---------------
Snappy压缩: 3396
Snappy解压缩: 3850
对象是否相等: true
---------------Lz4压缩---------------
Lz4压缩: 3358
Lz4解压缩: 3850
对象是否相等: true
---------------bzip2压缩---------------
bzip2压缩: 2119
bzip2解压缩: 3850
对象是否相等: true
---------------Deflate压缩---------------
Deflate压缩: 2167
Deflate解压缩: 3850
对象是否相等: true

Process finished with exit code 0

8 总结

通过上面几节的学习,对lz4有了大致的了解,它的压缩和解压缩效率是非常好的,压缩比相较于其他压缩工具来讲并不是很突出,其压缩比取决于压缩内容的重复率。

在压缩场景中,选择合适的压缩工具,各种压缩工具均有其利弊,扬其长、避其短,才能使得我们的工作更有效。文章来源地址https://www.toymoban.com/news/detail-432353.html

到了这里,关于Java实现数据压缩所有方式性能测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【优化技术专题】「性能优化系列」针对Java对象压缩及序列化技术的探索之路

    序列化和反序列化 序列化就是指把对象转换为字节码; 对象传递和保存时,保证对象的完整性和可传递性。把对象转换为有字节码,以便在网络上传输或保存在本地文件中; 反序列化就是指把字节码恢复为对象; 根据字节流中保存的对象状态及描述信息,通过反序列化重建

    2024年01月22日
    浏览(57)
  • 【金仓数据库】kingbase ES性能提升之传输压缩

    数据库应用场景复杂且多样,本文介绍金仓数据库在网络条件较差(小于10MB/s)场景,提供传输压缩特性进行性能提升。 当应用需要并发查询大量结果集时,容易出现网络资源争用问题。造成服务端CPU空闲而网络繁忙的状况,因为大结果集需要占用非常多的网络带宽,从而导

    2023年04月11日
    浏览(52)
  • 前端实现下载文件(包含压缩包下载)方式汇总

    默认最简单的下载方式是: window.open(后台接口API路径) ,但该方法弊端:因是新开窗口方式,前端展示上,每次会闪下。 此外,如果使用window.open(文件URL)方式: pdf、office文档、psd:直接下载。 图片、txt:新开窗口预览,不会下载;且txt预览,有时出现中文乱码问题。 一、

    2024年02月10日
    浏览(54)
  • 【接口测试】POST请求提交数据的三种方式及Postman实现

      POST请求是HTPP协议中一种常用的请求方法,它的使用场景是向客户端向服务器提交数据,比如登录、注册、添加等场景。另一种常用的请求方法是GET,它的使用场景是向服务器获取数据。 当前,POST请求提交数据的编码方式有三种: application/x-www-form-urlencoded multipart/form-dat

    2024年02月10日
    浏览(52)
  • 【接口/性能测试】Jmeter引用 jar包的三种方式(详细)

    实现对登录密码进行MD5加密 pom文件依赖 MD5Util类 package打包生成jar文件。 方式一:把jar包加入到classpath 添加jar包 login请求 beanshell脚本 发送请求后,从查看结果树中可以看到请求的密码加密了 方式二:把jar包放到lib/ext下 jmeter会自动从它的/lib和/lib/ext目录下的jar包中查找需要

    2024年02月15日
    浏览(41)
  • Java实现多数据源的方式

    1)在yml文件当中配置多数据源 2) 定义一个DataSourceConfig 配置类来配置两个数据源 3)自定义一个类 来 继承 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; ** 在类里面注入分别注入两个数据源** 4) 添加一个根据注解设置的动态数据源 5) 在service中使用指定的数据源 上面采

    2024年02月13日
    浏览(44)
  • java返回前端树形结构数据(2种实现方式)

    0.思想 首先找到一级目录(类别),然后从一级目录(类别)递归获取所有子目录(类别),并组合成为一个“目录树” 1.普通实现:controller层传的是0层,就是一级目录层,从这里开始往下递归。 2.stream流实现: 3.实体类集合专VO类集合的工具类 入参为未知类型的实体集合

    2024年02月04日
    浏览(35)
  • Java 数据结构篇-二叉树的深度优先遍历(实现:递归方式、非递归方式)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍    文章目录         1.0 二叉树的说明         1.1 二叉树的实现         2.0 二叉树的优先遍历说明         3.0 用递归方式实现二叉树遍历         3.1 用递归方式实现遍历 - 前序遍历         3.2 用递归

    2024年02月05日
    浏览(53)
  • Windows环境下通过 系统定时 执行脚本方式 压缩并备份文件夹 到其他数据盘

    压缩时需要使用7-zip进行调用,因此根据自己电脑进行安装 官网:https://www.7-zip.org/ 新建记事本文件,重命名为git_back_up.bat 注意:如果不设置可能会导致定时任务无法执行 开“控制面板-管理工具-本地安全策略”,选择“安全设置-本地策略-安全选项”,在右边列表中找到“

    2024年02月14日
    浏览(59)
  • ES删除索引中的所有数据(不删除索引结构)含curl删除方式

    场景:想只删除索引下的数据,不删除索引结构,(windows环境)服务器中没有postman工具 第一种:只删除索引中的所有数据,不删除索引结构 第二种:删除索引中的指定的数据,不删除索引结构 第三种:删除所有数据,删除索引结构 windows环境中curl方式删除 第一种:删除所有

    2024年02月11日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包