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