java内置的解压缩工具

简介

java关于压缩和解压缩的核心类就是Defalter(压缩)类和Inflater(解压)类,操作GZip和Zip文件也是基于这两个类。Tomcat对响应数据的压缩就是基于GZip。

使用Deflater和Inflater解压缩

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字节。

使用DeflaterOutputStream和InflaterOutputStream解压缩

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];
  }
}

输出结果为

before compress: 43435
after compress: 1168
after decompress: 43435

可以看到和使用Deflater压缩的效果是一样的。DeflaterOutputStream写入完成之后必须调用finish()方法。

/**
 * 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也是类似。

使用GZipOutputStream和GZipInputStream解压缩

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的检验数据。

可以看到Tomcat服务器对响应数据的压缩就使用到了GZipOutputStream。

posted @ 2020-12-12 15:26  strongmore  阅读(833)  评论(0编辑  收藏  举报