最近在使用Redis的时候,经常遇到一些不常用的大key,对存储有一些负担。就想着把大key压缩一下。压缩可以分很多种,比如拆分JSON字符串​, ​​压缩JSON字符串​,优化JSON体积​,流式处理大型JSON​和分段存储。

v拆分JSON字符串​

1.1按结构拆分​

数组拆分​​:若JSON包含大型数组,可将其拆分为多个小数组。

// 示例:将大数组拆分为多个子数组
JSONArray bigArray = new JSONArray(jsonString);
int chunkSize = 100;
for (int i = 0; i < bigArray.length(); i += chunkSize) {
JSONArray chunk = new JSONArray();
for (int j = i; j < Math.min(i + chunkSize, bigArray.length()); j++) {
chunk.put(bigArray.get(j));
}
String chunkJson = chunk.toString();
// 处理或保存chunkJson
}

​​对象拆分​​:若JSON是嵌套对象,可按层级拆分为子对象。

1.2按大小拆分(流式处理)​​

使用流式API(如Jackson的JsonParser)逐块读取JSON内容,避免一次性加载到内存:

JsonFactory factory = new JsonFactory();
try (JsonParser parser = factory.createParser(new File("large.json"))) {
while (parser.nextToken() != null) {
// 逐Token处理,如按特定条件拆分
}
}

v压缩JSON字符串​

2.1使用GZIP压缩​
import java.util.zip.GZIPOutputStream;
import java.io.ByteArrayOutputStream; public static byte[] compress(String data) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length());
try (GZIPOutputStream gzip = new GZIPOutputStream(bos)) {
gzip.write(data.getBytes());
}
return bos.toByteArray();
} // 压缩后的数据可用于传输或存储
byte[] compressed = compress(jsonString);
2.2使用Deflater压缩​
import java.util.zip.Deflater;

public static byte[] deflateCompress(String data) {
Deflater deflater = new Deflater();
deflater.setInput(data.getBytes());
deflater.finish();
byte[] buffer = new byte[1024];
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
deflater.end();
return outputStream.toByteArray();
}

v优化JSON体积​​

3.1移除无用空格​

使用紧凑格式(无缩进、换行):

new JSONObject(jsonString).toString(); // 默认紧凑格式
3.2​​缩短键名​

将长字段名替换为短名称:

{"n":"Alice","a":30} // 原始键名可能为"name"、"age"

v流式处理大型JSON​​

使用流式API逐步解析,避免内存溢出:

// Jackson流式API示例
JsonFactory factory = new JsonFactory();
try (JsonParser parser = factory.createParser(new File("large.json"))) {
JsonToken token;
while ((token = parser.nextToken()) != null) {
if (token == JsonToken.START_ARRAY) {
while (parser.nextToken() != JsonToken.END_ARRAY) {
// 逐条处理数组元素
JsonNode node = parser.readValueAsTree();
// 处理node...
}
}
}
}

v分页处理​

其实也是拆分,将数据拆成若干份

v实践方案

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.codec.binary.Base64;
import java.nio.charset.StandardCharsets; public class CompressHelper { private static final ObjectMapper objectMapper = new ObjectMapper(); /**
* 方式1:去除JSON中的空格/换行等冗余字符(文本压缩)
* @param formattedJson 格式化的JSON字符串(含空格换行)
* @return 紧凑格式的JSON字符串
* @throws IOException JSON解析异常
*/
public static String compressJsonByRemovingSpaces(String formattedJson) throws IOException {
JsonNode jsonNode = objectMapper.readTree(formattedJson);
return objectMapper.writeValueAsString(jsonNode);
} /**
* 方式2:使用GZIP算法对JSON字符串进行二进制压缩(适合网络传输)
* @param json 原始JSON字符串
* @return Base64编码的压缩后字符串(可直接传输)
* @throws IOException 压缩异常
*/
public static String compressJsonByGzip(String json) throws IOException {
try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(byteOut)) { gzipOut.write(json.getBytes("UTF-8"));
gzipOut.finish(); return Base64.encodeBase64String(byteOut.toByteArray());
}
} public static String decompressJson(String source) throws IOException {
byte[] compressedData = Base64.decodeBase64(source);
try (ByteArrayInputStream byteIn = new ByteArrayInputStream(compressedData);
GZIPInputStream gzipIn = new GZIPInputStream(byteIn);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream()) { // 读取压缩数据并解压缩
byte[] buffer = new byte[1024];
int len;
while ((len = gzipIn.read(buffer)) != -1) {
byteOut.write(buffer, 0, len);
}
return byteOut.toString(StandardCharsets.UTF_8.name());
}
}
}

v源码地址

https://github.com/toutouge/javademosecond/tree/master/hellolearn

作  者:请叫我头头哥


出  处:http://www.cnblogs.com/toutou/


关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!


版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。


特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信


声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

#comment_body_3242240 { display: none }

SpringBoot进阶教程(八十七)数据压缩的更多相关文章

  1. SpringBoot进阶教程(二十七)整合Redis之分布式锁

    在之前的一篇文章(<Java分布式锁,搞懂分布式锁实现看这篇文章就对了>),已经介绍过几种java分布式锁,今天来个Redis分布式锁的demo.redis 现在已经成为系统缓存的必备组件 ...

  2. SpringBoot进阶教程(六十七)RateLimiter限流

    在上一篇文章nginx限流配置中,我们介绍了如何使用nginx限流,这篇文章介绍另外一种限流方式---RateLimiter. v限流背景 在早期的计算机领域,限流技术(time limiting)被 ...

  3. SpringBoot进阶教程(六十八)Sentinel实现限流降级

    前面两篇文章nginx限流配置和SpringBoot进阶教程(六十七)RateLimiter限流,我们介绍了如何使用nginx和RateLimiter限流,这篇文章介绍另外一种限流方式---Senti ...

  4. SpringBoot进阶教程(七十四)整合ELK

    在上一篇文章<SpringBoot进阶教程(七十三)整合elasticsearch >,已经详细介绍了关于elasticsearch的安装与使用,现在主要来看看关于ELK的定义.安装及使用 ...

  5. SpringBoot进阶教程(二十九)整合Redis 发布订阅

    SUBSCRIBE, UNSUBSCRIBE 和 PUBLISH 实现了 发布/订阅消息范例,发送者 (publishers) 不用编程就可以向特定的接受者发送消息 (subscribers). Ra ...

  6. SpringBoot进阶教程(五十九)整合Codis

    上一篇博文<详解Codis安装与部署>中,详细介绍了codis的安装与部署,这篇文章主要介绍介绍springboot整合codis.如果之前看过<SpringBoot进阶教程(五十二 ...

  7. SpringBoot进阶教程 | 第四篇:整合Mybatis实现多数据源

    这篇文章主要介绍,通过Spring Boot整合Mybatis后如何实现在一个工程中实现多数据源.同时可实现读写分离. 准备工作 环境: windows jdk 8 maven 3.0 IDEA 创建 ...

  8. SpringBoot进阶教程(六十一)intellij idea project下建多个module搭建架构(下)

    在上一篇文章<SpringBoot进阶教程(六十)intellij idea project下建多个module(上)>中,我们已经介绍了在intellij idea中创建project之 ...

  9. SpringBoot进阶教程(六十四)注解大全

    在Spring1.x时代,还没出现注解,需要大量xml配置文件并在内部编写大量bean标签.Java5推出新特性annotation,为spring的更新奠定了基础.从Spring 2.X开始spri ...

  10. SpringBoot进阶教程(六十五)自定义注解

    在上一篇文章<SpringBoot进阶教程(六十四)注解大全>中介绍了springboot的常用注解,springboot提供的注解非常的多,这些注解简化了我们的很多操作.今天主要介绍介绍 ...

随机推荐

  1. 前端开发系列014-基础篇之Javascript面向对象(三)

    一.原型对象相关方法 ❏ in 关键字 ❏ instanceof ❏ hasOwnProperty方法 ❏ constructor构造器属性 ❏ isProtoTypeOf方法 in关键字 作用 用来 ...

  2. 90%的C#程序员都不知道的冷门语法,第5个简直神了!

    大家好,我是.NET修仙日记的掌门人.作为深耕C#多年的老司机,今天要给大家分享几个藏在Visual Studio角落里的语法瑰宝.这些语法不仅能让你的代码更简洁高效,还能在Code Review时让 ...

  3. 使用rclone将linux服务器上的文件夹同步到nextcloud

    最近公司在用nextcloud管理文件,我写了一个python脚本,领导想看中间生成的图片,让我把图片同步到nextcloud上.上网搜了一些方法,最终用rclone实现,以下是实现过程. 服务器版本 ...

  4. 基于 ETL 工具实现人大金仓数据库的数据迁移与整合实操指南

    在企业数字化转型的浪潮下,数据已经成为企业发展的核心资产.人大金仓数据库凭借其稳定可靠的性能,在国内众多企业中得到了广泛应用.但随着业务的不断拓展和系统的更新迭代,数据迁移与整合的需求也日益凸显.无论 ...

  5. NIO复习(2):channel

    上篇学习了NIO的buffer,继续来学习channel,类图如下(注:为了不让图看起来太复杂,隐藏了一些中间的接口) Channel派生了很多子接口,其中最常用的有FileChannel(用于文件操 ...

  6. C#/.NET/.NET Core技术前沿周刊 | 第 47 期(2025年7.14-7.20)

    前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...

  7. NGINX配置pdf文件可直接下载-九五小庞

    Nginx下载路径 http://nginx.org/en/download.html Nginx中的配置 server { listen 8888; server_name localhost; # ...

  8. 2023年4月最新全国省市区县和乡镇街道行政区划矢量边界坐标经纬度地图数据 shp geojson json

    发现个可以免费下载全国 geojson 数据的网站,推荐一下.支持全国.省级.市级.区/县级.街道/乡镇级以及各级的联动数据,支持导入矢量地图渲染框架中使用,例如:D3.Echarts等 geojso ...

  9. el-table合并相同数据的行

    // 表格列.行宽计算 arraySpanMethod: function (obj) { var prop = obj.column.property; var row = obj.row; var ...

  10. 图片和视频都可以去水印啦,ai去水印的简单两种方法

    有时候我们希望移除视频中的水印,但又不擅长使用专业软件,结果反而花费了很多时间和精力.这种情况下该怎么办呢? 今天给大家推荐两个方法: 一.在线去水印 Photopea是一款在线图像编辑器,界面和功能 ...