java关于压缩和解压缩的核心类就是Defalter(压缩)类和Inflater(解压)类,操做GZip和Zip文件也是基于这两个类。Tomcat对响应数据的压缩就是基于GZip。java
import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.InputStream; import java.util.zip.Deflater; import java.util.zip.Inflater; public class Client { public static void main(String[] args) throws Exception { byte[] bytes = readFromFile("D:/testdeflate.txt"); System.out.println("before compress: " + bytes.length); byte[] compressedBytes = compress(bytes); System.out.println("after compress: " + compressedBytes.length); byte[] decompressBytes = decompress(compressedBytes); System.out.println("after decompress: " + decompressBytes.length); } /** * 解压数据 * * @param bytes 源数据 * @return 压缩以后的数据 */ private static byte[] decompress(byte[] bytes) { Inflater inflater = new Inflater(); //设置待解压数据 inflater.setInput(bytes); byte[] buf = new byte[1024]; try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { //是否已解压完成 while (!inflater.finished()) { //解压 int len = inflater.inflate(buf); output.write(buf, 0, len); } //关闭资源 inflater.end(); return output.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return new byte[0]; } /** * 压缩数据 * * @param bytes 源数据 * @return 压缩以后的数据 */ private static byte[] compress(byte[] bytes) { Deflater deflater = new Deflater(); //设置待压缩数据 deflater.setInput(bytes); //表示压缩以当前输入内容结束,暂时不知道具体原理 deflater.finish(); byte[] buf = new byte[1024]; try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { //是否已压缩完成 while (!deflater.finished()) { //压缩 int len = deflater.deflate(buf); output.write(buf, 0, len); } //关闭资源 deflater.end(); return output.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return new byte[0]; } /** * 读取文件内容 * * @param filePath 文件路径 * @return 文件内容 */ private static byte[] readFromFile(String filePath) { int len = -1; byte[] buf = new byte[1024]; try (InputStream input = new BufferedInputStream(new FileInputStream(filePath)); ByteArrayOutputStream output = new ByteArrayOutputStream()) { while ((len = input.read(buf)) != -1) { output.write(buf, 0, len); } return output.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return new byte[0]; } }
输出结果为服务器
before compress: 43435 after compress: 1168 after decompress: 43435
能够看到数据从原来的43435字节压缩到了1168字节。code
import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; public class Client { public static void main(String[] args) throws IOException { byte[] bytes = readFromFile("D:/testdeflate.txt"); System.out.println("before compress: " + bytes.length); byte[] compressedBytes = readFromFileAndCompress("D:/testdeflate.txt"); System.out.println("after compress: " + compressedBytes.length); byte[] decompressBytes = readAndDecompress(compressedBytes); System.out.println("after decompress: " + decompressBytes.length); } /** * 读取文件内容并压缩 * * @param filePath 文件路径 * @return 文件内容 */ private static byte[] readFromFileAndCompress(String filePath) { int len = -1; byte[] buf = new byte[1024]; try (InputStream input = new BufferedInputStream(new FileInputStream(filePath)); ByteArrayOutputStream output = new ByteArrayOutputStream(); DeflaterOutputStream dos = new DeflaterOutputStream(output)) { //从输入流读取写入到输出流 while ((len = input.read(buf)) != -1) { dos.write(buf, 0, len); } //必须 dos.finish(); return output.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return new byte[0]; } /** * 读取文件内容 * * @param filePath 文件路径 * @return 文件内容 */ private static byte[] readFromFile(String filePath) { int len = -1; byte[] buf = new byte[1024]; try (InputStream input = new BufferedInputStream(new FileInputStream(filePath)); ByteArrayOutputStream output = new ByteArrayOutputStream()) { while ((len = input.read(buf)) != -1) { output.write(buf, 0, len); } return output.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return new byte[0]; } /** * 读取并解压缩 * * @param bytes 待解压数据 * @return 解压以后的数据 */ private static byte[] readAndDecompress(byte[] bytes) { int len = -1; byte[] buf = new byte[1024]; try (InputStream input = new InflaterInputStream(new ByteArrayInputStream(bytes)); ByteArrayOutputStream output = new ByteArrayOutputStream()) { while ((len = input.read(buf)) != -1) { output.write(buf, 0, len); } return output.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return new byte[0]; } }
输出结果为orm
before compress: 43435 after compress: 1168 after decompress: 43435
能够看到和使用Deflater压缩的效果是同样的。DeflaterOutputStream写入完成以后必须调用finish()方法。blog
/** * This class implements an output stream filter for compressing data in * the "deflate" compression format. It is also used as the basis for other * types of compression filters, such as GZIPOutputStream. * * @see Deflater * @author David Connelly * @since 1.1 */ public class DeflaterOutputStream extends FilterOutputStream { /** * 压缩类 */ protected Deflater def; /** * 重写了父类的write方法,先将数据压缩再写入 */ public void write(byte[] b, int off, int len) throws IOException { if (def.finished()) { throw new IOException("write beyond end of stream"); } if ((off | len | (off + len) | (b.length - (off + len))) < 0) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } if (!def.finished()) { def.setInput(b, off, len); while (!def.needsInput()) { deflate(); } } } /** * 数据压缩 */ protected void deflate() throws IOException { int len = def.deflate(buf, 0, buf.length); if (len > 0) { out.write(buf, 0, len); } } }
能够看到DeflaterOutputStream内部就是使用了Deflater来压缩数据,InflaterInputStream也是相似。ip
import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; public class Client { public static void main(String[] args) { byte[] bytes = readFromFile("D:/testdeflate.txt"); System.out.println("before compress: " + bytes.length); byte[] compressedBytes = readFromFileAndCompress("D:/testdeflate.txt"); System.out.println("after compress: " + compressedBytes.length); byte[] decompressBytes = readAndDecompress(compressedBytes); System.out.println("after decompress: " + decompressBytes.length); } /** * 读取文件内容 * * @param filePath 文件路径 * @return 文件内容 */ private static byte[] readFromFile(String filePath) { int len = -1; byte[] buf = new byte[1024]; try (InputStream input = new BufferedInputStream(new FileInputStream(filePath)); ByteArrayOutputStream output = new ByteArrayOutputStream()) { while ((len = input.read(buf)) != -1) { output.write(buf, 0, len); } return output.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return new byte[0]; } /** * 读取文件内容并压缩 * * @param filePath 文件路径 * @return 文件内容 */ private static byte[] readFromFileAndCompress(String filePath) { int len = -1; byte[] buf = new byte[1024]; try (InputStream input = new BufferedInputStream(new FileInputStream(filePath)); ByteArrayOutputStream output = new ByteArrayOutputStream(); GZIPOutputStream dos = new GZIPOutputStream(output)) { while ((len = input.read(buf)) != -1) { dos.write(buf, 0, len); } //必须 dos.finish(); return output.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return new byte[0]; } /** * 读取并解压 * * @param bytes 待解压数据 * @return 解压以后的数据 */ private static byte[] readAndDecompress(byte[] bytes) { int len = -1; byte[] buf = new byte[1024]; try (InputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes)); ByteArrayOutputStream output = new ByteArrayOutputStream()) { while ((len = input.read(buf)) != -1) { output.write(buf, 0, len); } return output.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return new byte[0]; } }
输出结果为资源
before compress: 43435 after compress: 1180 after decompress: 43435
能够看到使用GZip相比Deflater,压缩以后的数据多了一些字节,这是由于GZipOutputStream就是DeflaterOutputStream的扩展类,在数据头部加入了10个字节的header数据,尾部加入了8个字节的CRC32的检验数据。
input
能够看到Tomcat服务器对响应数据的压缩就使用到了GZipOutputStream。it