前言:
目前各位老铁们对“phpvariant”大体比较着重,兄弟们都需要学习一些“phpvariant”的相关内容。那么小编在网络上网罗了一些关于“phpvariant””的相关内容,希望各位老铁们能喜欢,朋友们一起来了解一下吧!在某些业务场景下,可能需要对字符串进行压缩与解压,压缩字符串可以使用 GZIPOutputStream 输出流来实现,而解压可以使用 GZIPInputStream 输入流来实现,下面先给出具体的参考代码,然后再分析其中的实现原理。
::: hljs-center
:::
1、代码实现
<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">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 ;2.2 字符串解压
压缩后的字符串解压缩的实现原理如下:
首先使用压缩后的字符串构建字节数组输入流 ByteArrayInputStream ;然后使用 ByteArrayInputStream 字节数组输入流构建 GZIPInputStream 压缩输入流, GZIPInputStream 类主要就是用来读取 GZIP 格式的压缩数据的,这个过程会对压缩数据进行解压,具体压缩的实现可以参考 GZIPInputStream 的父类 InflaterInputStream 和默认的解压器 Inflater 类的源码实现;从 GZIPInputStream 压缩输入流中读取数据,然后再写入到 ByteArrayOutputStream 字节数组输出流中;最后再将 ByteArrayOutputStream 字节数组输出流转换为 String ,得到解压后的字符串;
不论是字符串压缩还是字符串解压缩,最终将数据流转换为字符串时,都用到了 ByteArrayOutputStream 字节数组输出流。
2.3 字符编码
在压缩和解压的过程中,都需要先将字符串转换为字节流,然后再将字节流转换为字符串,转换的过程中会涉及到编码格式,比如在上面的示例代码中,使用到了两种编码格式: StandardCharsets.UTF_8 和 StandardCharsets.ISO_8859_1 ,压缩和解压的编码选择应该是一致的,否则可能会导致解压失败。
下面来简单分析一下 StandardCharsets 编码类。
<pre class="prettyprint hljs php" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">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() 方法,如下:
<pre class="prettyprint hljs gradle" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public static void main(String[] args) throws IOException { System.out.println(StandardCharsets.UTF_8.name()); System.out.println(StandardCharsets.UTF_8.displayName());}
输出的结果都是 UTF-8 ,如下:
<pre class="hljs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">UTF-8UTF-83、测试验证
下面来测试验证一下字符串的压缩与解压。
<pre class="prettyprint hljs gradle" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public static void main(String[] args) throws IOException { System.out.println(GzipUtils.compress("123456")); System.out.println(GzipUtils.decompress(compress("123456")));}
运行程序,输出结果如下:
<pre class="hljs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">342615 aÓr 123456
从输出结果可以看出,字符串被压缩后,如果直接输出,得到的将会是乱码。
标签: #phpvariant