JDK 之 Deflater 压缩与 Inflater 解压

简介: 在实际的应用场景中,特别是对外传输数据时,将原始数据压缩之后丢出去,可以说是非常常见的一个case了,平常倒是没有直接使用JDK原生的压缩工具类,使用Protosutff和Kryo的机会较多,正好在实际的工作场景中遇到了,现在简单的看下使用姿势

JDK 压缩与解压工具类



在实际的应用场景中,特别是对外传输数据时,将原始数据压缩之后丢出去,可以说是非常常见的一个case了,平常倒是没有直接使用JDK原生的压缩工具类,使用Protosutff和Kryo的机会较多,正好在实际的工作场景中遇到了,现在简单的看下使用姿势


I. 压缩与解压工具类



1. 基本实现


主要借助的就是Deflater, Inflater两个工具类,其使用姿势如下

public static String uncompress(byte[] input) throws IOException {
    Inflater inflater = new Inflater();
    inflater.setInput(input);
    ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length);
    try {
        byte[] buff = new byte[1024];
        while (!inflater.finished()) {
            int count = inflater.inflate(buff);
            baos.write(buff, 0, count);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        baos.close();
    }
    inflater.end();
    byte[] output = baos.toByteArray();
    return new String(output, "UTF-8");
}
public static byte[] compress(byte[] data) throws IOException {
    byte[] output;
    Deflater compress = new Deflater();
    compress.reset();
    compress.setInput(data);
    compress.finish();
    ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
    try {
        byte[] buf = new byte[1024];
        while (!compress.finished()) {
            int i = compress.deflate(buf);
            bos.write(buf, 0, i);
        }
        output = bos.toByteArray();
    } catch (Exception e) {
        output = data;
        e.printStackTrace();
    } finally {
        bos.close();
    }
    compress.end();
    return output;
}
复制代码


一个简单的测试

public static void main(String[] args) throws IOException {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < 200; i++) {
        builder.append('a' + (new Random().nextInt() * 26));
    }
    String text = builder.toString();
    byte[] compres = compress(text.getBytes());
    System.out.println(compres.length + " : " + text.getBytes().length);
    String res = uncompress(compres);
    System.out.println("uncompress! \n" + text + "\n" + res);
}
复制代码


输出结果

1011 : 1974
uncompress! 
1159641073884270587-148914555-876348695-140903655914152858511750740619-504526839109631208315104321891746743931-228808979-1303586499-19431155411964999751-1784318475-954798177-1812907183-831342707-3149322476028964551802022597-269963287-6384200011467670385844411707877038035412670417-1119826115558346219-959513147646693111435818855-32626587-18184494797054550038966016212145089137523302939171183465807867207-5294746515903446057333959811216956465-11772186456902770294071039871896527261-126190055310658640239029635411410052621945318513-1099749933-2044334159884087065-1705740759-1313321287-1408007761-12659778231544522691472523171153203782987609706919936632357801287155512488271333115291-1121944135941979389-179880545175884207196204559-2097788799145839653133892163716038492252042396151523357607329397509-2453452914618397691174247129-542507633-1893723573237001573-84175562119492726191070559557-875056377-1763237523-662399435-170798495-12405874171550890051-1938474621-701626601-1246867757-1138873077164155271023310391435811251050668025181338411-7641844471088518205-1570482881-1690731767-954924683-213656821149494003-544272515-9322840891981997411254437701-183054198720365002211448655569-54030518916444117051191350451-900732825-2072105047160877226512403288354302424851213478975-57604286986096457192173124564975571096304687-213425653510984804314132356831371957625714091709-327695077-182546427-372769058150182636433743131293942149315625331-1010625457741185365-81246881-565236593-1937214707-2090999425-1673181289-1110250756450022071917863643-127217577910228760391902441297-31318475-535669437-1151216791170962161121375401911260706331-1873591233-495048743-8876731551362670289-686442615-6752584831233249861-3467630691547253127-345092207-908370541-1788351797644350365-67770933-4703179231930520693138257968522450375-1171662023-5791753311816936409-1745781765-922801857281665531707439257928142703-367587763829971705455779401438501763-1398546079-606883161-924403277-1617582925-2005411841279115903
1159641073884270587-148914555-876348695-140903655914152858511750740619-504526839109631208315104321891746743931-228808979-1303586499-19431155411964999751-1784318475-954798177-1812907183-831342707-3149322476028964551802022597-269963287-6384200011467670385844411707877038035412670417-1119826115558346219-959513147646693111435818855-32626587-18184494797054550038966016212145089137523302939171183465807867207-5294746515903446057333959811216956465-11772186456902770294071039871896527261-126190055310658640239029635411410052621945318513-1099749933-2044334159884087065-1705740759-1313321287-1408007761-12659778231544522691472523171153203782987609706919936632357801287155512488271333115291-1121944135941979389-179880545175884207196204559-2097788799145839653133892163716038492252042396151523357607329397509-2453452914618397691174247129-542507633-1893723573237001573-84175562119492726191070559557-875056377-1763237523-662399435-170798495-12405874171550890051-1938474621-701626601-1246867757-1138873077164155271023310391435811251050668025181338411-7641844471088518205-1570482881-1690731767-954924683-213656821149494003-544272515-9322840891981997411254437701-183054198720365002211448655569-54030518916444117051191350451-900732825-2072105047160877226512403288354302424851213478975-57604286986096457192173124564975571096304687-213425653510984804314132356831371957625714091709-327695077-182546427-372769058150182636433743131293942149315625331-1010625457741185365-81246881-565236593-1937214707-2090999425-1673181289-1110250756450022071917863643-127217577910228760391902441297-31318475-535669437-1151216791170962161121375401911260706331-1873591233-495048743-8876731551362670289-686442615-6752584831233249861-3467630691547253127-345092207-908370541-1788351797644350365-67770933-4703179231930520693138257968522450375-1171662023-5791753311816936409-1745781765-922801857281665531707439257928142703-367587763829971705455779401438501763-1398546079-606883161-924403277-1617582925-2005411841279115903
复制代码


2. 注意事项


上面这个运作的还挺好,但在接入使用时,总是提示

java.util.zip.DataFormatException: incorrect header check, 因为接受的是第三方传递过来的压缩数据,比较坑爹的是对方就写了个Deflater压缩,然后什么都没有了,那么这个是啥原因呢?


其实看下Deflater的构造方法,发现还可以传一个boolean值(nowrap), 官方说明是

/**
 * Creates a new compressor using the specified compression level.
 * If 'nowrap' is true then the ZLIB header and checksum fields will
 * not be used in order to support the compression format used in
 * both GZIP and PKZIP.
 * @param level the compression level (0-9)
 * @param nowrap if true then use GZIP compatible compression
 */
public Deflater(int level, boolean nowrap) {
    this.level = level;
    this.strategy = DEFAULT_STRATEGY;
    this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap));
}
复制代码


简单来说,就是压缩时,如果nowrap为true,那么解压时也要为true;否则对不上时,就会抛异常


接下来简单对比下两种不同传参的情况,首先更新下工具类

public static String uncompress(byte[] input, boolean nowrap) throws IOException {
    Inflater inflater = new Inflater(nowrap);
    inflater.setInput(input);
    ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length);
    try {
        byte[] buff = new byte[1024];
        while (!inflater.finished()) {
            int count = inflater.inflate(buff);
            baos.write(buff, 0, count);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        baos.close();
    }
    inflater.end();
    byte[] output = baos.toByteArray();
    return new String(output);
}
public static byte[] compress(byte[] data, boolean nowrap) throws IOException {
    byte[] output;
    Deflater compress = new Deflater(Deflater.DEFAULT_COMPRESSION, nowrap);
    compress.reset();
    compress.setInput(data);
    compress.finish();
    ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
    try {
        byte[] buf = new byte[1024];
        while (!compress.finished()) {
            int i = compress.deflate(buf);
            bos.write(buf, 0, i);
        }
        output = bos.toByteArray();
    } catch (Exception e) {
        output = data;
        e.printStackTrace();
    } finally {
        bos.close();
    }
    compress.end();
    return output;
}
复制代码


测试如下

public static void main(String[] args) throws IOException {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < 1000; i++) {
        builder.append('a' + (new Random().nextInt() * 26));
    }
    String text = builder.toString();
    byte[] compres = compress(text.getBytes(), true);
    System.out.println(compres.length + " : " + text.getBytes().length);
    String res = uncompress(compres, true);
    System.out.println(res.equals(text));
    byte[] compres2 = compress(text.getBytes(), false);
    System.out.println(compres2.length + " : " + text.getBytes().length);
    String res2 = uncompress(compres2, false);
    System.out.println(res2.equals(text));
}
复制代码


输出结果如下,从大小来看,前者小那么一点点

5086 : 9985
true
5092 : 9985
true
复制代码


3. 小结


一般来说,jdk自带的压缩与解压,除了方便之外,可能优势并不是那么的大,这里盗一张网上的对比表格


以下来自: [java]序列化框架性能对比(kryo、hessian、java、protostuff)

优点 缺点
kryo 速度快,序列化后体积小 跨语言支持较复杂
hessian 默认支持跨语言 较慢
protostuff 速度快,基于protobuf 需静态编译
Protostuff-Runtime 无需静态编译,但序列化前需预先传入schema 不支持无默认构造函数的类,反序列化时需用户自己初始化序列化后的对象,其只负责将该对象进行赋值
jdk 使用方便,可序列化所有类 速度慢,占空间


其次,在使用java的压缩与解压时,需要注意下,nowrap这个参数,需要保持一致,否则会报错



相关文章
|
9月前
|
Oracle Java 关系型数据库
JDK的解压安装 - CentOS(结尾附视频)
JDK的解压安装 - CentOS(结尾附视频)
109 0
|
2月前
|
Java 应用服务中间件 开发工具
最简单JDK安装指南(小白也能一次性安装完成)
最简单JDK安装指南(小白也能一次性安装完成)
|
3月前
|
存储 Java Windows
Java21 JDK下载安装及Windows环境变量配置
JDK是Java的开发工具包,要进行Java学习或开发之前,需先下载安装,下载地址如下:提示:这网址里面有三个扩展名的文件,分别是“.zip”、“.exe”和“.msi”,鄙人选择的是.exe的文件,下方的安装和环境的配置也是安装该文件的安装程序进行的。
277 2
|
3月前
|
Java
安装JAVA_JDK快速入门
安装JAVA_JDK快速入门
|
8天前
|
Oracle Java 关系型数据库
Java 开发者必备:JDK 版本详解与选择策略(含安装与验证)
Oracle Java SE 支持路线图显示,JDK 8(LTS)支持至2030年,非LTS版本如9-11每6个月发布且支持有限。JDK 11(LTS)支持至2032年,而JDK 17及以上版本现在提供免费商用许可。LTS版本提供长达8年的支持,每2年发布一次。Oracle JDK与OpenJDK有多个社区和公司构建版本,如Adoptium、Amazon Corretto和Azul Zulu,它们在许可证、商业支持和更新方面有所不同。个人选择JDK时,可考虑稳定性、LTS、第三方兼容性和提供商支持。
23 0
|
15天前
|
Java Linux 开发工具
linux jdk的安装
linux jdk的安装
17 0
|
28天前
|
Java Linux
linux安装jdk环境
linux安装jdk环境
29 0
|
1月前
|
Java
jdk的安装与环境变量的配置
jdk的安装与环境变量的配置
17 0
|
1月前
|
NoSQL 关系型数据库 MySQL
Docker安装详细步骤及相关环境安装配置(mysql、jdk、redis、自己的私有仓库Gitlab 、C和C++环境以及Nginx服务代理)
Docker安装详细步骤及相关环境安装配置(mysql、jdk、redis、自己的私有仓库Gitlab 、C和C++环境以及Nginx服务代理)
214 0
|
1月前
|
Java 编译器 测试技术
滚雪球学Java(04):JDK、IntelliJ IDEA的安装和环境变量配置
【2月更文挑战第11天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!!
48 1