JDK 压缩与解压工具类 在实际的应用场景中,特别是对外传输数据时,将原始数据压缩之后丢出去,可以说是非常常见的一个case了,平常倒是没有直接使用JDK原生的压缩工具类,使用Protosutff和Kryo的机会较多,正好在实际的工作场景中遇到了,现在简单的看下使用姿势
I. 压缩与解压工具类 1. 基本实现 主要借助的就是Deflater, Inflater两个工具类,其使用姿势如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 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; } 
一个简单的测试
1 2 3 4 5 6 7 8 9 10 11 12 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); } 
输出结果
1 2 3 4 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), 官方说明是
1 2 3 4 5 6 7 8 9 10 11 12 13 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;否则对不上时,就会抛异常
接下来简单对比下两种不同传参的情况,首先更新下工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 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; } 
测试如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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)); } 
输出结果如下,从大小来看,前者小那么一点点
1 2 3 4 5086 : 9985 true 5092 : 9985 true 
3. 小结 一般来说,jdk自带的压缩与解压,除了方便之外,可能优势并不是那么的大,这里盗一张网上的对比表格
以下来自: [java]序列化框架性能对比(kryo、hessian、java、protostuff) 
优点 
缺点 
 
 
kryo 
速度快,序列化后体积小 
跨语言支持较复杂 
 
hessian 
默认支持跨语言 
较慢 
 
protostuff 
速度快,基于protobuf 
需静态编译 
 
Protostuff-Runtime 
无需静态编译,但序列化前需预先传入schema 
不支持无默认构造函数的类,反序列化时需用户自己初始化序列化后的对象,其只负责将该对象进行赋值 
 
jdk 
使用方便,可序列化所有类 
速度慢,占空间 
 
 
其次,在使用java的压缩与解压时,需要注意下,nowrap这个参数,需要保持一致,否则会报错
II. 其他 一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明 尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
3. 扫描关注 一灰灰blog 
知识星球