溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java壓縮、序列化及編碼轉(zhuǎn)義的用法

發(fā)布時間:2021-06-28 14:50:14 來源:億速云 閱讀:251 作者:chen 欄目:大數(shù)據(jù)

本篇內(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í)!

向AI問一下細節(jié)

免責(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)容。

AI