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。