GZIPOutputStream & GZIPInputStream 数据压缩&解压

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

最近接手了一批性能优化…
遇到这样一个接口:已经把能优化的部分都优化了(包括业务逻辑批处理、数据预处理、数据缓存、减少查表字段、加表索引等)。

但是,这个接口里有个外部调用会去查询3000+数据,得到的数据大小约为1.5M,耗时:2s
外部系统接口执行时间为:0.8s
那么就意味着...数据传输消耗了:1s+

解决方法:
外部系统将出参:压缩
自己系统将得到数据:解压
从而减少数据传输的时间

其他方面:减少出参的冗余字段

一、最终走上了压缩的路 GZIPOutputStream

将json字符串压缩,再加密(保证安全性)

    public static String getCompressionStr(String jsonStr) throws Exception {
        
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gos = new GZIPOutputStream(out);

        gos.write(jsonStr.getBytes(StandardCharsets.UTF_8));
        gos.close();

        byte[] encodeBytes = Base64.getEncoder().encode(out.toByteArray());
        return new String(encodeBytes);
   

二、收到数据进行解压 GZIPInputStream

将收到的字符串进行解密,再解压

    public static String getDecompressionStr(String compressionStr) throws Exception {
        byte[] decodedBytes = Base64.getDecoder().decode(compressionStr);
        
        GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(decodedBytes));
        BufferedReader bf = new BufferedReader(new InputStreamReader(gis, StandardCharsets.UTF_8));

        StringBuilder outStr = new StringBuilder();
        String line;

        while ((line = bf.readLine()) != null) {
            outStr.append(line);
        }

        return StringEscapeUtils.unescapeJava(outStr.toString());
    }

三、测试Demo

**** 重要提示 *******
1:验证的时候,日志记得分开打印。日志很大,不然不好查看日志数据
2:调整idea的 setting -> Editor -> General -> Console
Override console cycle buffer size 调整为10240

public class Demo {

    public static void main(String[] args) {
        String jsonStr = getJsonStr();
        System.out.println(jsonStr);
        
        try {
            String compressionStr = getCompressionStr(jsonStr);
//            System.out.println(compressionStr);

            String decompressionStr = getDecompressionStr(compressionStr);
//            System.out.println(decompressionStr);

            List<User> users = JSONArray.parseArray(decompressionStr, User.class);
            System.out.println(users.get(100));
            System.out.println(users.get(100).getUserId());
            System.out.println(users.get(100).getName());
            System.out.println(users.get(100).getAddress());


        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }
	
	/**
	 * 随便创建10000个对象,userId,name,address
	 **/
    public static String getJsonStr() {
        List<User> users = new ArrayList<>();
        String address = "让我感到为难的 是挣扎的自由\n" +
                "分别总是在九月 回忆是思念的愁\n" +
                "深秋嫩绿的垂柳 亲吻着我额头\n" +
                "在那座阴雨的小城里 我从未忘记你\n" +
                "成都 带不走的 只有你\n" +
                "和我在成都的街头走一走 喔…\n" +
                "直到所有的灯都熄灭了也不停留";
        for (int i = 0; i < 10000; i++) {
            users.add(new User((long) (i + 1), "张三" + (i + 1), address));
        }
        return JSONArray.toJSONString(users);
    }

四、验证结果

在这里插入图片描述
1:10000个对象的大小为 3328KB
2:压缩后的大小为 80KB
3:解压后的大小为 3328KB
4:解压后数据可转为对象(支持嵌套对象),正常使用

            List<User> users = JSONArray.parseArray(decompressionStr, User.class);

            System.out.println(users.get(100));
            System.out.println(users.get(100).getUserId());
            System.out.println(users.get(100).getName());
            System.out.println(users.get(100).getAddress());
    对应的输出结果为:
    
User(userId=101, name=张三101, address=让我感到为难的 是挣扎的自由
分别总是在九月 回忆是思念的愁
深秋嫩绿的垂柳 亲吻着我额头
在那座阴雨的小城里 我从未忘记你
成都 带不走的 只有你
和我在成都的街头走一走 喔…
直到所有的灯都熄灭了也不停留)

101

张三101

让我感到为难的 是挣扎的自由
分别总是在九月 回忆是思念的愁
深秋嫩绿的垂柳 亲吻着我额头
在那座阴雨的小城里 我从未忘记你
成都 带不走的 只有你
和我在成都的街头走一走 喔…
直到所有的灯都熄灭了也不停留
            

总结

性能优化是真的心累。
特别是产品经理的沙雕设计(一次性拿3000条数据就不合理,为了强行实现功能)
最后说下优化的结果:产线上12s的接口,最终降低至2s

另外说明下:
文章内除了StringEscapeUtils以外,仅用到了jdk自带的库

但是在lang3里StringEscapeUtils已经Deprecated了。可以换成common-text
import org.apache.commons.text.StringEscapeUtils;
//import org.apache.commons.lang3.StringEscapeUtils;

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.10.0</version>
    </dependency>
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Java中可以使用`java.util.zip.GZIPOutputStream`类对byte数组进行gzip压缩,使用`java.util.zip.GZIPInputStream`类对压缩后的byte数组进行解压缩。 以下是一个示例代码,将一个字符串进行gzip压缩,并将压缩后的byte数组再进行解压缩,最后输出解压缩后的字符串: ```java import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; public class GzipExample { public static void main(String[] args) throws IOException { String inputString = "This is a test string for gzip compression and decompression."; byte[] inputBytes = inputString.getBytes(StandardCharsets.UTF_8); // 压缩 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream); gzipOutputStream.write(inputBytes); gzipOutputStream.close(); byte[] compressedBytes = outputStream.toByteArray(); // 解压缩 ByteArrayInputStream inputStream = new ByteArrayInputStream(compressedBytes); GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream); ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = gzipInputStream.read(buffer)) > 0) { output.write(buffer, 0, len); } String outputString = new String(output.toByteArray(), StandardCharsets.UTF_8); System.out.println(outputString); // 输出: This is a test string for gzip compression and decompression. } } ``` 在上面的代码中,我们先将字符串转换为byte数组,然后使用`GZIPOutputStream`将byte数组进行压缩,压缩后的byte数组输出到一个`ByteArrayOutputStream`中。接着,我们再使用`GZIPInputStream`将压缩后的byte数组进行解压缩,解压后的byte数组输出到另一个`ByteArrayOutputStream`中,最后将解压缩后的byte数组转换为字符串。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值