您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“java壓縮、序列化及編碼轉(zhuǎn)義的用法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“java壓縮、序列化及編碼轉(zhuǎn)義的用法”吧!
1、服務(wù)端編碼時,壓縮報文、編碼轉(zhuǎn)義、摘要信息等都是常見場景,本次針對對應(yīng)相關(guān)工具進行分類
2、壓縮報文:GZIP
Gzip是常見的壓縮報文算法工具,默認使用DEFLATE實現(xiàn),此為LZ77+hufman的結(jié)合體。即先通過LZ77進行相同字符歸類壓縮在使用哈夫曼編碼整理成樹,完成壓縮。PS:LZ77算法和hufman算法可參見:https://www.cnblogs.com/kuang17/p/7193124.html
LZ77算法可概述為掃描整個報文,找出相同字符串并使用前面的代替后面的。這樣通過字符串和位移及長度實現(xiàn)初步壓縮,可見,重復(fù)率越高壓縮比越大。
hufman算法可概述為掃描整個報文,重復(fù)率越少的字符,離根節(jié)點越遠,這樣越是離根節(jié)點近,重復(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編碼 二進制轉(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)義二進制 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)報文較大時,會存在冗余讀,導(dǎo)致解壓后出現(xiàn)冗余內(nèi)容! 2.原因在于倒數(shù)第二部分內(nèi)容 為較長字符串時,內(nèi)容超長 3.當(dāng)解析最后一部分內(nèi)容時 由于內(nèi)容較短,只覆蓋了前N個長度的內(nèi)容, 但是write是寫了全部的 }*/ int n; while ((n = zipIs.read(temp)) >= 0){ baOs.write(temp, 0, n); } //3.base64 二進制恢復(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)庫\",\"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\":\"身份證號\",\"required\":1}],\"paramResList\":[{\"code\":\"phone\",\"createTime\":\"2019-10-09 14:58:21\",\"dataType\":\"int\",\"modifyTime\":\"2019-10-09 15:01:24\",\"name\":\"手機號\"},{\"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)庫\"}}],\"realDsList\":[]}"; System.out.println(GZipUtil.unCompress(GZipUtil.compress(a))); } }
3、base64編碼可謂是最常見的加解密算法,如上GzipUtil工具類中就夾雜了base64編碼相關(guān)內(nèi)容:一種基于64個可打印字符[通過52個大小寫英文字母、10個數(shù)字和+\兩個符號進行]來表示二進制數(shù)據(jù)的方法。其不可讀性的特點通常用來進行簡單的加密操作,同時其二進制ASCII碼的特點也經(jīng)常用來平衡GBK、UTF8等編碼造成的不一致,如郵件應(yīng)用。
Base64編碼也有變種如UrlEnCode等js編碼。最簡單應(yīng)用可使用java.util.Base64 工具包
4、信息摘要MD5,最新研究表明Md5已不是不可破解的算法。 但是其作為復(fù)雜算法的摘要功能和壓縮功能仍然具有廣闊的應(yīng)用場景。畢竟解碼一段Md5還是很復(fù)雜的,如果你的內(nèi)容不是國家級機密,我相信沒有人會耗盡心機去破解那段"毫無意義"的內(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 { // 拿到一個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個元素 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對象圖(Object graph)序列化框架。
java的序列化是通過ObjectOutPutStream實現(xiàn)的,較慢。kryo因為指定注冊了序列化的對象,速度會快,經(jīng)測試為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會保證此方法絕對只調(diào)用一次 private Singleton(){ singleton = new Kryo(); // 如果沒有多層次的對象引用相互引用,設(shè)為false,提高性能 singleton.setReferences(false); // 注冊序列化/反序列化的類 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 * <p/> */ public class KryoUtil { private static final String DEFAULT_ENCODING = "UTF-8"; //每個線程的 Kryo 實例 private static final ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>() { @Override protected Kryo initialValue() { Kryo kryo = new Kryo(); /** * 不要輕易改變這里的配置!更改之后,序列化的格式就會發(fā)生變化, * 上線的同時就必須清除 Redis 里的所有緩存, * 否則那些緩存再回來反序列化的時候,就會報錯 */ //支持對象循環(huán)引用(否則會棧溢出) kryo.setReferences(true); //默認值就是 true,添加此行的目的是為了提醒維護者,不要改變這個配置 //不強制要求注冊類(注冊行為無法保證多個 JVM 內(nèi)同一個類的注冊編號相同;而且業(yè)務(wù)系統(tǒng)中大量的 Class 也難以一一注冊) kryo.setRegistrationRequired(false); //默認值就是 false,添加此行的目的是為了提醒維護者,不要改變這個配置 //Fix the NPE bug when deserializing Collections. ((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()) .setFallbackInstantiatorStrategy(new StdInstantiatorStrategy()); return kryo; } }; /** * 獲得當(dāng)前線程的 Kryo 實例 * * @return 當(dāng)前線程的 Kryo 實例 */ public static Kryo getInstance() { return kryoLocal.get(); } //----------------------------------------------- // 序列化/反序列化對象,及類型信息 // 序列化的結(jié)果里,包含類型的信息 // 反序列化時不再需要提供類型 // (推薦使用下面一組方法) //----------------------------------------------- /** * 將對象【及類型】序列化為字節(jié)數(shù)組 * * @param obj 任意對象 * @param <T> 對象的類型 * @return 序列化后的字節(jié)數(shù)組 */ public static <T> 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(); } /** * 將對象【及類型】序列化為 String * 利用了 Base64 編碼 * * @param obj 任意對象 * @param <T> 對象的類型 * @return 序列化后的字符串 */ public static <T> String writeToString(T obj) { try { return new String(Base64.encodeBase64(writeToByteArray(obj)), DEFAULT_ENCODING); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } } /** * 將字節(jié)數(shù)組反序列化為原對象 * * @param byteArray writeToByteArray 方法序列化后的字節(jié)數(shù)組 * @param <T> 原對象的類型 * @return 原對象 */ @SuppressWarnings("unchecked") public static <T> T readFromByteArray(byte[] byteArray) { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); Input input = new Input(byteArrayInputStream); Kryo kryo = getInstance(); return (T) kryo.readClassAndObject(input); } /** * 將 String 反序列化為原對象 * 利用了 Base64 編碼 * * @param str writeToString 方法序列化后的字符串 * @param <T> 原對象的類型 * @return 原對象 */ public static <T> T readFromString(String str) { try { return readFromByteArray(Base64.decodeBase64(str.getBytes(DEFAULT_ENCODING))); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } } //----------------------------------------------- // 下面一組方法與上面的一組的區(qū)別在于 只序列化/反序列化對象 // 序列化的結(jié)果里,不包含類型的信息 //----------------------------------------------- /** * 將對象序列化為字節(jié)數(shù)組 * @param obj 任意對象 * @param <T> 對象的類型 * @return 序列化后的字節(jié)數(shù)組 */ public static <T> 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(); } /** * 將對象序列化為 String * 利用了 Base64 編碼 * * @param obj 任意對象 * @param <T> 對象的類型 * @return 序列化后的字符串 */ public static <T> String writeObjectToString(T obj) { try { return new String(Base64.encodeBase64(writeObjectToByteArray(obj)), DEFAULT_ENCODING); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); } } /** * 將字節(jié)數(shù)組反序列化為原對象 * * @param byteArray writeToByteArray 方法序列化后的字節(jié)數(shù)組 * @param clazz 原對象的 Class * @param <T> 原對象的類型 * @return 原對象 */ public static <T> T readObjectFromByteArray(byte[] byteArray, Class<T> clazz) { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); Input input = new Input(byteArrayInputStream); Kryo kryo = getInstance(); return kryo.readObject(input, clazz); } /** * 將 String 反序列化為原對象 * 利用了 Base64 編碼 * * @param str writeToString 方法序列化后的字符串 * @param clazz 原對象的 Class * @param <T> 原對象的類型 * @return 原對象 */ public static <T> T readObjectFromString(String str, Class<T> 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> KRYO_THREAD_LOCAL = new ThreadLocal<Kryo>() { @Override protected Kryo initialValue() { Kryo kryo = new Kryo(); kryo.register(Mt.class); return kryo; } }; public static <T> 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> T in(byte[] bytes, Class<T> 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
到此,相信大家對“java壓縮、序列化及編碼轉(zhuǎn)義的用法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。