Java利用Gzip对字符串进行压缩与解压
Posted 然笑后端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java利用Gzip对字符串进行压缩与解压相关的知识,希望对你有一定的参考价值。
在某些业务场景下,可能需要对字符串进行压缩与解压,压缩字符串可以使用 GZIPOutputStream
输出流来实现,而解压可以使用 GZIPInputStream
输入流来实现,下面先给出具体的参考代码,然后再分析其中的实现原理。
::: hljs-center
:::
1、代码实现
package com.magic.zip;
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 GzipUtils
/**
* 压缩字符串
*
* @param str 需要压缩的源字符串
* @return 压缩后的字符串
*/
public static String compress(String str)
if (null == str || str.length() <= 0)
return str;
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(out))
// 将字符串以字节的形式写入到 GZIP 压缩输出流中
gzip.write(str.getBytes(StandardCharsets.UTF_8));
gzip.close();
return out.toString(StandardCharsets.ISO_8859_1.name());
catch (IOException e)
e.printStackTrace();
return str;
/**
* 解压缩字符串
*
* @param str 待解压的字符串
* @return 解压后的字符串
*/
public static String decompress(String str)
if (str == null || str.length() == 0)
return str;
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes(StandardCharsets.ISO_8859_1));
GZIPInputStream gunzip = new GZIPInputStream(in))
byte[] buffer = new byte[256];
int n;
// 从 GZIP 压缩输入流读取字节数据到 buffer 数组中
while ((n = gunzip.read(buffer)) >= 0)
out.write(buffer, 0, n);
return out.toString(StandardCharsets.UTF_8.name());
catch (IOException e)
e.printStackTrace();
return str;
2、原理分析
2.1 字符串压缩
字符串压缩的实现原理如下:
- 首先构建
GZIPOutputStream
压缩输出流,然后将需要压缩的字符串写入输出流中,在写入GZIPOutputStream
输出流的时候,就会使用deflate
压缩算法对字符串进行压缩,具体的实现可以参考GZIPOutputStream
的父类DeflaterOutputStream
和默认的压缩器Deflater
类的源码实现; - 将
GZIPOutputStream
压缩输出流转换为ByteArrayOutputStream
字节数组输出流; - 最后再将
ByteArrayOutputStream
字节数组输出流转换为字符串String
;
关于 GZIPOutputStream
和 ByteArrayOutputStream
类的源码分析,可以参考我写的另外两篇文章:
2.2 字符串解压
压缩后的字符串解压缩的实现原理如下:
- 首先使用压缩后的字符串构建字节数组输入流
ByteArrayInputStream
; - 然后使用
ByteArrayInputStream
字节数组输入流构建GZIPInputStream
压缩输入流,GZIPInputStream
类主要就是用来读取GZIP
格式的压缩数据的,这个过程会对压缩数据进行解压,具体压缩的实现可以参考GZIPInputStream
的父类InflaterInputStream
和默认的解压器Inflater
类的源码实现; - 从
GZIPInputStream
压缩输入流中读取数据,然后再写入到ByteArrayOutputStream
字节数组输出流中; - 最后再将
ByteArrayOutputStream
字节数组输出流转换为String
,得到解压后的字符串;
关于 GZIPInputStream
、ByteArrayInputStream
和 ByteArrayOutputStream
类的源码分析,可以参考我写的另外三篇文章:
- 【水煮 JDK 源码】- GZIPInputStream 类源码分析
- 【水煮 JDK 源码】- ByteArrayInputStream 类源码分析
- 【水煮 JDK 源码】- ByteArrayOutputStream 类源码分析
不论是字符串压缩还是字符串解压缩,最终将数据流转换为字符串时,都用到了 ByteArrayOutputStream
字节数组输出流。
2.3 字符编码
在压缩和解压的过程中,都需要先将字符串转换为字节流,然后再将字节流转换为字符串,转换的过程中会涉及到编码格式,比如在上面的示例代码中,使用到了两种编码格式:StandardCharsets.UTF_8
和 StandardCharsets.ISO_8859_1
,压缩和解压的编码选择应该是一致的,否则可能会导致解压失败。
下面来简单分析一下 StandardCharsets
编码类。
public final class StandardCharsets
/** 构造函数为私有的,不能被实例化 */
private StandardCharsets()
throw new AssertionError("No java.nio.charset.StandardCharsets instances for you!");
/** US-ASCII(7位 ASCII 编码\\ISO646-US\\Basic Latin) */
public static final Charset US_ASCII = Charset.forName("US-ASCII");
/** ISO-8859-1(ISO 拉丁字母 编码\\ISO-LATIN-1) */
public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
/** UTF-8(八位 UCS 转换格式) */
public static final Charset UTF_8 = Charset.forName("UTF-8");
/** UTF-16BE(十六位 UCS 转换格式, 大端字节序) */
public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
/** UTF-16LE(十六位 UCS 转换格式, 小端字节序) */
public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
/** UTF-16(十六位 UCS 转换格式,由可选字节顺序标记标识的字节顺序) */
public static final Charset UTF_16 = Charset.forName("UTF-16");
StandardCharsets
类位于 java.nio.charset
包下,它是一个标准字符集常量定义类,一共定义了6种字符集 Charset
,有常见的 UTF-8
和 ISO-8859-1
,在平时的编码过程中,如果有使用到编码字符集,可以直接使用 StandardCharsets
,如果需要获取字符集的名称,可以调用 Charset
的 name()
方法或者 displayName()
方法,如下:
public static void main(String[] args) throws IOException
System.out.println(StandardCharsets.UTF_8.name());
System.out.println(StandardCharsets.UTF_8.displayName());
输出的结果都是 UTF-8
,如下:
UTF-8
UTF-8
3、测试验证
下面来测试验证一下字符串的压缩与解压。
public static void main(String[] args) throws IOException
System.out.println(GzipUtils.compress("123456"));
System.out.println(GzipUtils.decompress(compress("123456")));
运行程序,输出结果如下:
342615 aÓr
123456
从输出结果可以看出,字符串被压缩后,如果直接输出,得到的将会是乱码。
以上是关于Java利用Gzip对字符串进行压缩与解压的主要内容,如果未能解决你的问题,请参考以下文章