日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何压缩Json格式数据,减少Json数据的体积?

發(fā)布時間:2023/12/20 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何压缩Json格式数据,减少Json数据的体积? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、背景

最近剛剛做完一個中文漢字筆畫排序的功能,鏈接如下:

  • 【我的Android進階之旅】Android實現(xiàn)中文漢字筆劃(筆畫)排序、中文拼音排序、英文排序的國家地區(qū)選擇界面
  • 【我的Java開發(fā)學習之旅】如何實現(xiàn)中文漢字進行筆劃(筆畫)排序?
  • https://github.com/ouyangpeng/ChinesePinyinSortAndStrokeSort

其中優(yōu)化之后,將數(shù)據(jù)庫的內(nèi)容,序列化成為了json數(shù)據(jù),然后通過解析json數(shù)據(jù),拿到漢字筆畫的相關(guān)信息。但是未處理前的json文件,體積較大,有2.13Mb,因此需要壓縮才行。

部分數(shù)據(jù)如下所示:

{"33828": {"code": "33828","name": "螢","order": "7298","strokeSum": "11"},"22920": {"code": "22920","name": "媽","order": "1051","strokeSum": "6"},"20718": {"code": "20718","name": "僮","order": "13341","strokeSum": "14"},"30615": {"code": "30615","name": "瞗","order": "15845","strokeSum": "16"},"36969": {"code": "36969","name": "適","order": "13506","strokeSum": "14"} }
  • 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

二、常規(guī)壓縮json

2.1 未處理前的json文件

未處理前的json文件,格式好看但是體積較大。


未處理前的json文件,一共占用125414行

未處理的原始json文件大小為2.13Mb

2.2 將JSON壓縮成一行,去掉換行和空格字符

在Android Studio中打開,如下所示:

將JSON壓縮成一行,去掉換行和空格字符后的json文件大小為:1.39Mb,只之前的2.13Mb小了整整0.74Mb,這個在移動端是很可觀的優(yōu)化!

2.3 將JSON的key進行縮短

json 是 key-value 結(jié)構(gòu),如果定義好規(guī)范,則可以將 key 盡量縮短,甚至是無意義的字母,但前提是文檔一定要寫清楚,避免不必要的麻煩。

比如之前的 key-value結(jié)構(gòu)如下所示:

{"33828": {"code": "33828","name": "螢","order": "7298","strokeSum": "11"},"22920": {"code": "22920","name": "媽","order": "1051","strokeSum": "6"},"20718": {"code": "20718","name": "僮","order": "13341","strokeSum": "14"},"30615": {"code": "30615","name": "瞗","order": "15845","strokeSum": "16"},"36969": {"code": "36969","name": "適","order": "13506","strokeSum": "14"} }
  • 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

現(xiàn)在我們將key進行優(yōu)化,使用

c 代替 code
n 代替 name
o 代替 order
s 代替 strokeSum

將JSON的key進行縮短優(yōu)化后的json文件大小為:1.77Mb,只之前的2.13Mb小了整整0.36Mb,這個在移動端是很可觀的優(yōu)化!

然后再將縮短key之后的文件,重復【2.2 將JSON壓縮成一行,去掉換行和空格字符】的操作。

再看一看文件大小為1.04Mb,比最開始的原始數(shù)據(jù)2.13Mb小了整整1.09Mb,這個在移動端是很可觀的優(yōu)化!

當然這樣key的名字變化了,對應(yīng)解析Json的java實體bean也要修改一下。

因為我使用的是jackson來進行json解析的,所以使用注解@JsonProperty來表示一下修改的json文件對應(yīng)原來的java bean里面的屬性,這樣解析的時候就不會出錯了。

2.4 常規(guī)總結(jié)

經(jīng)過上面的常規(guī)操作,
我們的json文件大小減少到了1.04Mb
比最開始的原始數(shù)據(jù)2.13Mb
小了整整1.09Mb

壓縮率為51.174%,壓縮后體積為原來的48.826%

已經(jīng)算很給力了,但是這個json文件還是有1.04Mb啊,是否還可以進行壓縮呢?答案是肯定的,我們下面介紹下使用算法對該json文件進行壓縮。

三、使用壓縮算法進行壓縮

3.1 使用Deflater壓縮json,Inflater解壓json

Deflater 是同時使用了LZ77算法哈夫曼編碼的一個無損數(shù)據(jù)壓縮算法

我們可以使用 java 提供的 Deflater 和 Inflater 類對 json 進行壓縮和解壓縮,下面是工具類

package com.oyp.sort.utils;

import android.support.annotation.Nullable;
import android.util.Base64;

import java.io.ByteArrayOutputStream;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

/**

  • DeflaterUtils 壓縮字符串
    /
    public class DeflaterUtils {
    /*

    • 壓縮
      /
      public static String zipString(String unzipString) {
      /*

      • https://www.yiibai.com/javazip/javazip_deflater.html#article-start
      • 0 ~ 9 壓縮等級 低到高
      • public static final int BEST_COMPRESSION = 9; 最佳壓縮的壓縮級別。
      • public static final int BEST_SPEED = 1; 壓縮級別最快的壓縮。
      • public static final int DEFAULT_COMPRESSION = -1; 默認壓縮級別。
      • public static final int DEFAULT_STRATEGY = 0; 默認壓縮策略。
      • public static final int DEFLATED = 8; 壓縮算法的壓縮方法(目前唯一支持的壓縮方法)。
      • public static final int FILTERED = 1; 壓縮策略最適用于大部分數(shù)值較小且數(shù)據(jù)分布隨機分布的數(shù)據(jù)。
      • public static final int FULL_FLUSH = 3; 壓縮刷新模式,用于清除所有待處理的輸出并重置拆卸器。
      • public static final int HUFFMAN_ONLY = 2; 僅用于霍夫曼編碼的壓縮策略。
      • public static final int NO_COMPRESSION = 0; 不壓縮的壓縮級別。
      • public static final int NO_FLUSH = 0; 用于實現(xiàn)最佳壓縮結(jié)果的壓縮刷新模式。
      • public static final int SYNC_FLUSH = 2; 用于清除所有未決輸出的壓縮刷新模式; 可能會降低某些壓縮算法的壓縮率。

      */
      //使用指定的壓縮級別創(chuàng)建一個新的壓縮器。
      Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
      //設(shè)置壓縮輸入數(shù)據(jù)。
      deflater.setInput(unzipString.getBytes());
      //當被調(diào)用時,表示壓縮應(yīng)該以輸入緩沖區(qū)的當前內(nèi)容結(jié)束。
      deflater.finish();

      final byte[] bytes = new byte[256];
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream(256);

      while (!deflater.finished()) {
      //壓縮輸入數(shù)據(jù)并用壓縮數(shù)據(jù)填充指定的緩沖區(qū)。
      int length = deflater.deflate(bytes);
      outputStream.write(bytes, 0, length);
      }
      //關(guān)閉壓縮器并丟棄任何未處理的輸入。
      deflater.end();
      return Base64.encodeToString(outputStream.toByteArray(), Base64.NO_PADDING);
      }

    /**

    • 解壓縮
      */
      @Nullable
      public static String unzipString(String zipString) {
      byte[] decode = Base64.decode(zipString, Base64.NO_PADDING);
      //創(chuàng)建一個新的解壓縮器 https://www.yiibai.com/javazip/javazip_inflater.html
      Inflater inflater = new Inflater();
      //設(shè)置解壓縮的輸入數(shù)據(jù)。
      inflater.setInput(decode);

      final byte[] bytes = new byte[256];
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream(256);
      try {
      //finished() 如果已到達壓縮數(shù)據(jù)流的末尾,則返回true。
      while (!inflater.finished()) {
      //將字節(jié)解壓縮到指定的緩沖區(qū)中。
      int length = inflater.inflate(bytes);
      outputStream.write(bytes, 0, length);
      }
      } catch (DataFormatException e) {
      e.printStackTrace();
      return null;
      } finally {
      //關(guān)閉解壓縮器并丟棄任何未處理的輸入。
      inflater.end();
      }

      return outputStream.toString();
      }
      }

  • 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
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

3.1.1 壓縮原始的stroke.json數(shù)據(jù)

然后我們先將原始的stroke.json數(shù)據(jù)壓縮成deFlaterStrokeJson.json。

//原始文件 stroke.jsonString strokeJson = LocalFileUtils.getStringFormAsset(context, "stroke.json");mapper = JSONUtil.toCollection(strokeJson, HashMap.class, String.class, Stroke.class);// 使用 Deflater 加密String deFlaterStrokeJson = DeflaterUtils.zipString(strokeJson);writeFile(deFlaterStrokeJson,"deFlaterStrokeJson.json");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其中 writeFile方法是寫入到sdcard的方法。

private static void writeFile(String mapperJson, String fileName) {Writer write = null;try {File file = new File(Environment.getExternalStorageDirectory(), fileName);Log.d(TAG, "file.exists():" + file.exists() + " file.getAbsolutePath():" + file.getAbsolutePath());// 如果父目錄不存在,創(chuàng)建父目錄if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}// 如果已存在,刪除舊文件if (file.exists()) {file.delete();}file.createNewFile();// 將格式化后的字符串寫入文件write = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");write.write(mapperJson);write.flush();write.close();} catch (Exception e) {Log.e(TAG, "e = " + Log.getStackTraceString(e));}finally {if (write != null){try {write.close();} catch (IOException e) {Log.e(TAG, "e = " + Log.getStackTraceString(e));}}}}
  • 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

運行完畢之后,將sdcard中的deFlaterStrokeJson.json導出來,放到assets目錄下,以備后續(xù)解析使用。

使用Deflater壓縮json,壓縮后大小為 387KB,比上一次的1067KB,又少了很多很多。

經(jīng)過Deflater壓縮和Base64編碼之后的deFlaterStrokeJson.json文件,如下所示:

3.1.2 還原成原始的stroke.json數(shù)據(jù)

關(guān)壓縮還不行,我們得使用壓縮后的json文件數(shù)據(jù)啊,因此我們還需要將壓縮后的json數(shù)據(jù)進行解壓,操作如下所示:

//使用 Inflater 解密 String deFlaterStrokeJson = LocalFileUtils.getStringFormAsset(context, "deFlaterStrokeJson.json"); String strokeJson = DeflaterUtils.unzipString(deFlaterStrokeJson); mapper = JSONUtil.toCollection(strokeJson, HashMap.class, String.class, Stroke.class);
  • 1
  • 2
  • 3
  • 4

解壓之后運行一切正常!完美!

3.1.3 Deflater壓縮總結(jié)

經(jīng)過上面的常規(guī)操作,
我們的json文件大小減少到了387KB
比剛才未使用壓縮算法的原始數(shù)據(jù)1067KB
小了整整680KB

壓縮率為63.73%,壓縮后體積為原來的36.27%

優(yōu)化步驟體積
1.未處理的原始json2.13MB
2.將JSON壓縮成一行,去掉換行和空格字符1.39MB
3.將JSON的key進行縮短1.04MB
4.使用Deflater壓縮json,Base64編碼0.38MB

3.2 使用Gzip壓縮解壓json

在我封裝的http庫里面,有對請求json數(shù)據(jù)進行Gzip壓縮,對服務(wù)器返回的json數(shù)據(jù)進行Gzip解壓。這里也來試一下Gzip壓縮json。

編寫一個 Gzip壓縮解壓并使用Base64進行編碼工具類

package com.oyp.sort.utils;

import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**

  • Gzip壓縮解壓并使用Base64進行編碼工具類
    /
    public class GzipUtil {
    private static final String TAG = “GzipUtil”;
    /*

    • 將字符串進行g(shù)zip壓縮
    • @param data
    • @param encoding
    • @return
      */
      public static String compress(String data, String encoding) {
      if (data null || data.length() 0) {
      return null;
      }
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      GZIPOutputStream gzip;
      try {
      gzip = new GZIPOutputStream(out);
      gzip.write(data.getBytes(encoding));
      gzip.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      return Base64.encodeToString(out.toByteArray(), Base64.NO_PADDING);
      }

    public static String uncompress(String data, String encoding) {
    if (TextUtils.isEmpty(data)) {
    return null;
    }
    byte[] decode = Base64.decode(data, Base64.NO_PADDING);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ByteArrayInputStream in = new ByteArrayInputStream(decode);
    GZIPInputStream gzipStream = null;
    try {
    gzipStream = new GZIPInputStream(in);
    byte[] buffer = new byte[256];
    int n;
    while ((n = gzipStream.read(buffer)) >= 0) {
    out.write(buffer, 0, n);
    }
    } catch (IOException e) {
    Log.e(TAG, "e = " + Log.getStackTraceString(e));
    } finally {
    try {
    out.close();
    if (gzipStream != null) {
    gzipStream.close();
    }
    } catch (IOException e) {
    Log.e(TAG, "e = " + Log.getStackTraceString(e));
    }

    <span class="token punctuation">}</span><span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span>out<span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Charset<span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span>encoding<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    }

}

  • 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
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

3.2.1 壓縮原始的stroke.json數(shù)據(jù)

//原始文件 stroke.json String strokeJson = LocalFileUtils.getStringFormAsset(context, "stroke.json"); mapper = JSONUtil.toCollection(strokeJson, HashMap.class, String.class, Stroke.class); // 使用 GZIP 壓縮 String gzipStrokeJson = GzipUtil.compress(strokeJson,CHARSET_NAME); writeFile(gzipStrokeJson,"gzipStrokeJson.json");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

運行完畢之后,將sdcard中的gzipStrokeJson.json導出來,放到assets目錄下,以備后續(xù)解析使用。

導出來的gzipStrokeJson.json文件為405kb,沒有比剛才使用Deflater壓縮json后大小為 387KB優(yōu)秀!

3.2.2 還原成原始的stroke.json數(shù)據(jù)

關(guān)壓縮還不行,我們得使用壓縮后的json文件數(shù)據(jù)啊,因此我們還需要將壓縮后的json數(shù)據(jù)進行解壓,操作如下所示:

//使用 GZIP 解壓 String gzipStrokeJson = LocalFileUtils.getStringFormAsset(context, "gzipStrokeJson.json"); String strokeJson = GzipUtil.uncompress(gzipStrokeJson,CHARSET_NAME); mapper = JSONUtil.toCollection(strokeJson, HashMap.class, String.class, Stroke.class);
  • 1
  • 2
  • 3
  • 4

解壓之后,json解析一切正常!

3.2.3 Gzip壓縮總結(jié)

經(jīng)過上面的常規(guī)操作,
我們的json文件大小減少到了405kb
雖然比不上剛才的Deflater壓縮:387KB
但是比剛才未使用壓縮算法的原始數(shù)據(jù)1067KB
小了整整662KB

壓縮率為62.04%,壓縮后體積為原來的37.95%,也是不錯的!

四、 其他壓縮算法

除了上面的算法之外,我們還可以使用很多其他的壓縮算法,進一步壓縮json的體積。我們的原始json中還是有很多重復的key值可以進行優(yōu)化的,下面的算法中有部分可以進行key優(yōu)化!

https://web-resource-optimization.blogspot.com/2011/06/json-compression-algorithms.html

常見的json壓縮算法有CJSON與HPack,其原理都是將key和value進行抽離,節(jié)省掉部分的重復的key值造成的空間消耗。

4.1 CJSON

CJSON 的壓縮算法, 主要是將資料抽離成 Template 與 Value,節(jié)省掉重復的 “Key 值”.

原始JSON:

[{"x": 100,"y": 100},{"x": 100,"y": 100,"width": 200,"height": 150},{} ]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12


CJSON壓縮后:

{"templates": [[0, "x", "y"],[1, "width", "height"]],"values": [{"values": [1, 100, 100]},{"values": [2, 100, 100, 200, 150]},{}] }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4.2 HPack

HPack 的壓縮算法, 也是將 Key, Value 抽離, 陣列中第一個值, 就是 HPack 的 Template, 后面依序就是 Value.

[{"name": "Andrea","age": 31,"gender": "Male","skilled": true},{"name": "Eva","age": 27,"gender": "Female","skilled": true},{"name": "Daniele","age": 26,"gender": "Male","skilled": false} ]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

壓縮之后的數(shù)據(jù)

[["name","age","gender","skilled"],["Andrea",31,"Male",true],["Eva",27,"Female",true],["Daniele",26,"Male",false] ]
  • 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

兩種方法都是主要講json 的 鍵抽出來統(tǒng)一建成索引,只是最后的格式不同。

HPack 簡化后的格式比CJSON 少了許多字符,所以HPack 的壓縮效率比較高。數(shù)據(jù)量越大,效果越明顯,應(yīng)用場景也更加有意義。

如果 JSON 內(nèi)容太少, CJSON的資料可能反而會比較多。

壓縮效果

下圖來自:https://www.oschina.net/p/jsonhpack

五、參考資料

  • https://web-resource-optimization.blogspot.com/2011/06/json-compression-algorithms.html

  • https://github.com/WebReflection/json.hpack/wiki

  • 移動Web開發(fā),數(shù)據(jù)壓縮,后端壓縮傳輸?shù)膉son格式數(shù)據(jù)

  • JSON壓縮算法 JSON.hpack

  • json.hpack

  • JSON壓縮:JSONMinify

  • json 壓縮算法

  • 壓縮 json 的一些嘗試

  • 極限壓縮 json 文件 大小

  • https://github.com/WebReflection/JSONH

  • https://github.com/twitter/hpack

  • 該優(yōu)化的項目源代碼:https://github.com/ouyangpeng/ChinesePinyinSortAndStrokeSort/commits/master


作者:歐陽鵬 歡迎轉(zhuǎn)載,與人分享是進步的源泉!

總結(jié)

以上是生活随笔為你收集整理的如何压缩Json格式数据,减少Json数据的体积?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。