新聞中心
本篇內(nèi)容主要講解“java壓縮、序列化及編碼轉(zhuǎn)義的用法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“java壓縮、序列化及編碼轉(zhuǎn)義的用法”吧!
創(chuàng)新互聯(lián)自2013年起,先為磐安等服務(wù)建站,磐安等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為磐安企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
1、服務(wù)端編碼時(shí),壓縮報(bào)文、編碼轉(zhuǎn)義、摘要信息等都是常見場(chǎng)景,本次針對(duì)對(duì)應(yīng)相關(guān)工具進(jìn)行分類
2、壓縮報(bào)文:GZIP
Gzip是常見的壓縮報(bào)文算法工具,默認(rèn)使用DEFLATE實(shí)現(xiàn),此為L(zhǎng)Z77+hufman的結(jié)合體。即先通過LZ77進(jìn)行相同字符歸類壓縮在使用哈夫曼編碼整理成樹,完成壓縮。PS:LZ77算法和hufman算法可參見:https://www.cnblogs.com/kuang17/p/7193124.html
LZ77算法可概述為掃描整個(gè)報(bào)文,找出相同字符串并使用前面的代替后面的。這樣通過字符串和位移及長(zhǎng)度實(shí)現(xiàn)初步壓縮,可見,重復(fù)率越高壓縮比越大。
hufman算法可概述為掃描整個(gè)報(bào)文,重復(fù)率越少的字符,離根節(jié)點(diǎn)越遠(yuǎn),這樣越是離根節(jié)點(diǎn)近,重復(fù)率就越高,形成的hufman同樣遵循上述原則:即重復(fù)率越高壓縮比越大
附j(luò)ava代碼:
import lombok.extern.slf4j.Slf4j; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Base64; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; /** * @author ysma 2019-10-08 */ @Slf4j public class GZipUtil { private static final String EN_CODING = "utf-8"; /**壓縮*/ public static String compress(String dataMsg){ try { //1.base64編碼 二進(jìn)制轉(zhuǎn)義 byte[] base64Str = Base64.getEncoder().encode(dataMsg.getBytes(EN_CODING)); //2.zip壓縮 ByteArrayOutputStream baOs = new ByteArrayOutputStream(); GZIPOutputStream zipOs = new GZIPOutputStream(baOs, true); zipOs.write(base64Str); zipOs.flush(); zipOs.close();//關(guān)閉流 輸出緩存區(qū)內(nèi)容 //3.獲取并轉(zhuǎn)義壓縮內(nèi)容 return Base64.getEncoder().encodeToString(baOs.toByteArray()); } catch (IOException e) { log.error("GZipUtil.compress 壓縮異常", e); throw new RuntimeException("GZipUtil.compress 壓縮異常", e); } } /**解壓縮*/ public static String unCompress(String dataMsg){ //1.轉(zhuǎn)義二進(jìn)制 byte[] base64Bytes = Base64.getDecoder().decode(dataMsg.getBytes()); try { //1.zip解壓縮 ByteArrayOutputStream baOs = new ByteArrayOutputStream(); ByteArrayInputStream baIs = new ByteArrayInputStream(base64Bytes); GZIPInputStream zipIs = new GZIPInputStream(baIs); byte[] temp = new byte[256]; /*while (zipIs.read(temp) >=0){ baOs.write(temp); 1.當(dāng)報(bào)文較大時(shí),會(huì)存在冗余讀,導(dǎo)致解壓后出現(xiàn)冗余內(nèi)容! 2.原因在于倒數(shù)第二部分內(nèi)容 為較長(zhǎng)字符串時(shí),內(nèi)容超長(zhǎng) 3.當(dāng)解析最后一部分內(nèi)容時(shí) 由于內(nèi)容較短,只覆蓋了前N個(gè)長(zhǎng)度的內(nèi)容, 但是write是寫了全部的 }*/ int n; while ((n = zipIs.read(temp)) >= 0){ baOs.write(temp, 0, n); } //3.base64 二進(jìn)制恢復(fù) byte[] originMsg = Base64.getDecoder().decode(baOs.toByteArray()); return new String(originMsg); } catch (IOException e) { log.error("GZipUtil.unCompress 解壓縮異常", e); throw new RuntimeException("GZipUtil.unCompress 解壓縮異常", e); } } public static void main(String[] args) { String a ="{\"extendDsList\":[{\"datasource\":{\"code\":\"first_internal_1\",\"createTime\":\"2019-10-09 14:58:21\",\"description\":\"行內(nèi)第一數(shù)據(jù)源\",\"modifyTime\":\"2019-10-09 16:55:25\",\"name\":\"行內(nèi)第一數(shù)據(jù)源\",\"providerCode\":\"internal_database\",\"providerInfo\":\"{\\\"jdbcUrl\\\":\\\"jdbc:MySQL://10.2.1.106:3306/data_engine\\\",\\\"password\\\":\\\"Y1R1MTIzNDU2\\\",\\\"userName\\\":\\\"ctu\\\"}\",\"providerName\":\"數(shù)據(jù)聚合聯(lián)調(diào)庫(kù)\",\"providerType\":\"MYSQL\",\"querySql\":\"select code, name, url, source from name_list_info where code = #{code}\",\"serviceTtl\":7,\"serviceUrl\":\"\",\"status\":1,\"type\":4},\"paramReqList\":[{\"code\":\"name\",\"createTime\":\"2019-10-09 14:58:21\",\"dataType\":\"string\",\"modifyTime\":\"2019-10-09 15:01:30\",\"name\":\"名稱\",\"required\":1},{\"code\":\"id\",\"createTime\":\"2019-10-09 14:58:21\",\"dataType\":\"long\",\"modifyTime\":\"2019-10-09 15:01:34\",\"name\":\"身份證號(hào)\",\"required\":1}],\"paramResList\":[{\"code\":\"phone\",\"createTime\":\"2019-10-09 14:58:21\",\"dataType\":\"int\",\"modifyTime\":\"2019-10-09 15:01:24\",\"name\":\"手機(jī)號(hào)\"},{\"code\":\"rank\",\"createTime\":\"2019-10-09 14:58:21\",\"dataType\":\"string\",\"modifyTime\":\"2019-10-09 15:01:19\",\"name\":\"排位分\"}],\"provider\":{\"code\":\"internal_database\",\"createTime\":\"2019-10-09 14:58:09\",\"modifyTime\":\"2019-10-09 14:58:09\",\"name\":\"數(shù)據(jù)聚合聯(lián)調(diào)庫(kù)\"}}],\"realDsList\":[]}"; System.out.println(GZipUtil.unCompress(GZipUtil.compress(a))); } }
3、base64編碼可謂是最常見的加解密算法,如上GzipUtil工具類中就夾雜了base64編碼相關(guān)內(nèi)容:一種基于64個(gè)可打印字符[通過52個(gè)大小寫英文字母、10個(gè)數(shù)字和+\兩個(gè)符號(hào)進(jìn)行]來表示二進(jìn)制數(shù)據(jù)的方法。其不可讀性的特點(diǎn)通常用來進(jìn)行簡(jiǎn)單的加密操作,同時(shí)其二進(jìn)制ASCII碼的特點(diǎn)也經(jīng)常用來平衡GBK、UTF8等編碼造成的不一致,如郵件應(yīng)用。
Base64編碼也有變種如UrlEnCode等js編碼。最簡(jiǎn)單應(yīng)用可使用java.util.Base64 工具包
4、信息摘要MD5,最新研究表明Md5已不是不可破解的算法。 但是其作為復(fù)雜算法的摘要功能和壓縮功能仍然具有廣闊的應(yīng)用場(chǎng)景。畢竟解碼一段Md5還是很復(fù)雜的,如果你的內(nèi)容不是國(guó)家級(jí)機(jī)密,我相信沒有人會(huì)耗盡心機(jī)去破解那段"毫無意義"的內(nèi)容。
附代碼[32位和16位摘要]:
import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Hex; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Objects; /** * @author ysma md5工具 */ @Slf4j public class Md5Util { public static void main(String[] args) { String a = "{\"ysma\":\"dx\",\"hello\":\"world\"}"; String b = hexBit32(a); System.out.println(b); String c = hexBit16(b); System.out.println(c); } public static byte[] digest(String data){ try { // 拿到一個(gè)MD5轉(zhuǎn)換器 MessageDigest messageDigest =MessageDigest.getInstance("MD5"); // 輸入的字符串轉(zhuǎn)換成字節(jié)數(shù)組 byte[] inputByteArray = data.getBytes(); // inputByteArray是輸入字符串轉(zhuǎn)換得到的字節(jié)數(shù)組 messageDigest.update(inputByteArray); // 轉(zhuǎn)換并返回結(jié)果,也是字節(jié)數(shù)組,包含16個(gè)元素 return messageDigest.digest(); } catch (NoSuchAlgorithmException e) { log.error("Md5Util.stringMD5 exception", e); return null; } } public static String hexBit32(String data) { // 字符數(shù)組轉(zhuǎn)換成字符串返回 return Hex.encodeHexString(Objects.requireNonNull(digest(data)), false); } public static String hexBit16(String data) { // 字符數(shù)組轉(zhuǎn)換成字符串返回 return hexBit32(data).substring(8, 24); } }
5、序列化kryo:Kryo是一種快速高效的Java對(duì)象圖(Object graph)序列化框架。
java的序列化是通過ObjectOutPutStream實(shí)現(xiàn)的,較慢。kryo因?yàn)橹付ㄗ?cè)了序列化的對(duì)象,速度會(huì)快,經(jīng)測(cè)試為java版的1/5。
代碼收集:
import com.esotericsoftware.kryo.Kryo; public class KryoSingleton{ private KryoSingleton(){} public static Kryo getInstance(){ return Singleton.INSTANCE.getInstance(); } private static enum Singleton{ INSTANCE; private Kryo singleton; //JVM會(huì)保證此方法絕對(duì)只調(diào)用一次 private Singleton(){ singleton = new Kryo(); // 如果沒有多層次的對(duì)象引用相互引用,設(shè)為false,提高性能 singleton.setReferences(false); // 注冊(cè)序列化/反序列化的類 singleton.register(SceneLayout.class); singleton.register(SceneLayoutMethod.class); } public Kryo getInstance(){ return singleton; } } } -------------------------------------------------------------------------------- import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import org.apache.commons.codec.binary.Base64; import org.objenesis.strategy.StdInstantiatorStrategy; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; /** * Kryo Utils * */ public class KryoUtil { private static final String DEFAULT_ENCODING = "UTF-8"; //每個(gè)線程的 Kryo 實(shí)例 private static final ThreadLocalkryoLocal = new ThreadLocal () { @Override protected Kryo initialValue() { Kryo kryo = new Kryo(); /** * 不要輕易改變這里的配置!更改之后,序列化的格式就會(huì)發(fā)生變化, * 上線的同時(shí)就必須清除 redis 里的所有緩存, * 否則那些緩存再回來反序列化的時(shí)候,就會(huì)報(bào)錯(cuò) */ //支持對(duì)象循環(huán)引用(否則會(huì)棧溢出) kryo.setReferences(true); //默認(rèn)值就是 true,添加此行的目的是為了提醒維護(hù)者,不要改變這個(gè)配置 //不強(qiáng)制要求注冊(cè)類(注冊(cè)行為無法保證多個(gè) JVM 內(nèi)同一個(gè)類的注冊(cè)編號(hào)相同;而且業(yè)務(wù)系統(tǒng)中大量的 Class 也難以一一注冊(cè)) kryo.setRegistrationRequired(false); //默認(rèn)值就是 false,添加此行的目的是為了提醒維護(hù)者,不要改變這個(gè)配置 //Fix the NPE bug when deserializing Collections. ((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()) .setFallbackInstantiatorStrategy(new StdInstantiatorStrategy()); return kryo; } }; /** * 獲得當(dāng)前線程的 Kryo 實(shí)例 * * @return 當(dāng)前線程的 Kryo 實(shí)例 */ public static Kryo getInstance() { return kryoLocal.get(); } //----------------------------------------------- // 序列化/反序列化對(duì)象,及類型信息 // 序列化的結(jié)果里,包含類型的信息 // 反序列化時(shí)不再需要提供類型 // (推薦使用下面一組方法) //----------------------------------------------- /** * 將對(duì)象【及類型】序列化為字節(jié)數(shù)組 * * @param obj 任意對(duì)象 * @param 對(duì)象的類型 * @return 序列化后的字節(jié)數(shù)組 */ public static byte[] writeToByteArray(T obj) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Output output = new Output(byteArrayOutputStream); Kryo kryo = getInstance(); kryo.writeClassAndObject(output, obj); output.flush(); return byteArrayOutputStream.toByteArray(); } /** * 將對(duì)象【及類型】序列化為 String * 利用了 Base64 編碼 * * @param obj 任意對(duì)象 * @param 對(duì)象的類型 * @return 序列化后的字符串 */ public static String writeToString(T obj) { try { return new String(Base64.encodeBase64(writeToByteArray(obj)), DEFAULT_ENCODING); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } } /** * 將字節(jié)數(shù)組反序列化為原對(duì)象 * * @param byteArray writeToByteArray 方法序列化后的字節(jié)數(shù)組 * @param 原對(duì)象的類型 * @return 原對(duì)象 */ @SuppressWarnings("unchecked") public static T readFromByteArray(byte[] byteArray) { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); Input input = new Input(byteArrayInputStream); Kryo kryo = getInstance(); return (T) kryo.readClassAndObject(input); } /** * 將 String 反序列化為原對(duì)象 * 利用了 Base64 編碼 * * @param str writeToString 方法序列化后的字符串 * @param 原對(duì)象的類型 * @return 原對(duì)象 */ public static T readFromString(String str) { try { return readFromByteArray(Base64.decodeBase64(str.getBytes(DEFAULT_ENCODING))); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } } //----------------------------------------------- // 下面一組方法與上面的一組的區(qū)別在于 只序列化/反序列化對(duì)象 // 序列化的結(jié)果里,不包含類型的信息 //----------------------------------------------- /** * 將對(duì)象序列化為字節(jié)數(shù)組 * @param obj 任意對(duì)象 * @param 對(duì)象的類型 * @return 序列化后的字節(jié)數(shù)組 */ public static byte[] writeObjectToByteArray(T obj) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Output output = new Output(byteArrayOutputStream); Kryo kryo = getInstance(); kryo.writeObject(output, obj); output.flush(); return byteArrayOutputStream.toByteArray(); } /** * 將對(duì)象序列化為 String * 利用了 Base64 編碼 * * @param obj 任意對(duì)象 * @param 對(duì)象的類型 * @return 序列化后的字符串 */ public static String writeObjectToString(T obj) { try { return new String(Base64.encodeBase64(writeObjectToByteArray(obj)), DEFAULT_ENCODING); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } } /** * 將字節(jié)數(shù)組反序列化為原對(duì)象 * * @param byteArray writeToByteArray 方法序列化后的字節(jié)數(shù)組 * @param clazz 原對(duì)象的 Class * @param 原對(duì)象的類型 * @return 原對(duì)象 */ public static T readObjectFromByteArray(byte[] byteArray, Class clazz) { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); Input input = new Input(byteArrayInputStream); Kryo kryo = getInstance(); return kryo.readObject(input, clazz); } /** * 將 String 反序列化為原對(duì)象 * 利用了 Base64 編碼 * * @param str writeToString 方法序列化后的字符串 * @param clazz 原對(duì)象的 Class * @param 原對(duì)象的類型 * @return 原對(duì)象 */ public static T readObjectFromString(String str, Class clazz) { try { return readObjectFromByteArray(Base64.decodeBase64(str.getBytes(DEFAULT_ENCODING)), clazz); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } } } ================= =================分割線============================== import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import com.etonenet.esms.Mt; public class KryoUtil { public static final int KRYO_MSISDN_FILTER_LIST = 10; public static final int KRYO_MATCH = 11; // Kryo instance is not threadsafe, but expensive, so that is why it is // placed in a ThreadLocal. public static final ThreadLocal KRYO_THREAD_LOCAL = new ThreadLocal () { @Override protected Kryo initialValue() { Kryo kryo = new Kryo(); kryo.register(Mt.class); return kryo; } }; public static byte[] out(T object) { Kryo kryo = KRYO_THREAD_LOCAL.get(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Output output = new Output(byteArrayOutputStream); kryo.writeObject(output, object); output.flush(); output.close(); return byteArrayOutputStream.toByteArray(); } public static T in(byte[] bytes, Class clazz) { Kryo kryo = KRYO_THREAD_LOCAL.get(); Input input = new Input(new ByteArrayInputStream(bytes)); return kryo.readObject(input, clazz); } }
參見:https://www.cnblogs.com/benwu/articles/4826268.html
https://blog.csdn.net/lzj1005642974/article/details/77991408
https://blog.csdn.net/fuwenshen/article/details/98485865
到此,相信大家對(duì)“java壓縮、序列化及編碼轉(zhuǎn)義的用法”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
網(wǎng)頁(yè)名稱:java壓縮、序列化及編碼轉(zhuǎn)義的用法
文章起源:http://fisionsoft.com.cn/article/ghscgs.html