您的位置:首页 > 编程语言 > Java开发

java gzip 内存压缩

2016-01-22 17:43 615 查看
java 网络通讯中,为了节省带宽,可能需要将数据压缩之后再传输,正常过程如下

1. 读取原始文件 IO流

2. 用压缩工具压缩写入文件

3. 读取压缩文件IO 流

4. 传输压缩 IO 流

5. 删除压缩文件

这样一来就涉及到临时压缩文件的保存,保存完还需要删除压缩文件, 为了方便,我们直接将2、5步去除,直接将原始文件IO流压缩成压缩流,然后传输

代码如下(代码依赖于 Apache Commons Compress )

下载地址:http://commons.apache.org/proper/commons-compress/download_compress.cgi

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import org.apache.commons.compress.compressors.CompressorOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipParameters;
import org.apache.commons.compress.utils.CharsetNames;

/**
* gzip 压缩二进制,不写文件并返回二进制
* 修改自 org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream
* @author ysq
*
*/
public class GzipByteUtil extends CompressorOutputStream {

/** Header flag indicating a file name follows the header */
private static final int FNAME = 1 << 3;

/** Header flag indicating a comment follows the header */
private static final int FCOMMENT = 1 << 4;

/** The underlying stream 因为该方法不需要写文件,所以不需要输出 */
//private OutputStream out;

/** Deflater used to compress the data */
private final Deflater deflater;

/** The buffer receiving the compressed data from the deflater */
private final byte[] deflateBuffer = new byte[512];

/** Indicates if the stream has been closed */
private boolean closed;

/** The checksum of the uncompressed data */
private final CRC32 crc = new CRC32();

private byte[] compressedByte;

/**
* Creates a gzip compressed output stream with the default parameters.
*/
public GzipByteUtil() throws IOException {
this(new GzipParameters());
}

/**
* 不需要写文件所以不需要 out 对象
*
* @since 1.7
*/
public GzipByteUtil(GzipParameters parameters) throws IOException {
//this.out = out;
this.deflater = new Deflater(parameters.getCompressionLevel(), true);

writeHeader(parameters);
}

/**
* 返回压缩后的完整二进制
* @return
*/
public byte[] getCompressedByte() {
return compressedByte;
}

/**
* 头文件写文件,改为返回头文件二进制
* @param parameters
* @throws IOException
*/
private void writeHeader(GzipParameters parameters) throws IOException {
String filename = parameters.getFilename();
String comment = parameters.getComment();

ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.putShort((short) GZIPInputStream.GZIP_MAGIC);
buffer.put((byte) Deflater.DEFLATED); // compression method (8: deflate)
buffer.put((byte) ((filename != null ? FNAME : 0) | (comment != null ? FCOMMENT : 0))); // flags
buffer.putInt((int) (parameters.getModificationTime() / 1000));

// extra flags
int compressionLevel = parameters.getCompressionLevel();
if (compressionLevel == Deflater.BEST_COMPRESSION) {
buffer.put((byte) 2);
} else if (compressionLevel == Deflater.BEST_SPEED) {
buffer.put((byte) 4);
} else {
buffer.put((byte) 0);
}

buffer.put((byte) parameters.getOperatingSystem());

compressedByte = buffer.array();
//out.write(compressedByte);

if (filename != null) {
byte[] nameByte = filename.getBytes(CharsetNames.ISO_8859_1);

ByteBuffer nbf = ByteBuffer.allocate(nameByte.length + 1);

nbf.put(nameByte);
nbf.put((byte) 0);

appendCompressedByte(nbf.array());

//out.write(filename.getBytes(CharsetNames.ISO_8859_1));
//out.write(nbf.array());
}

if (comment != null) {
byte[] commentByte = comment.getBytes(CharsetNames.ISO_8859_1);

ByteBuffer combf = ByteBuffer.allocate(commentByte.length + 1);

combf.put(commentByte);
combf.put((byte) 0);

appendCompressedByte(combf.array());

//out.write(combf.array());
}
}

/** ===================================================================================================== **/

@Override
public void write(int b) throws IOException {
write(new byte[]{(byte) (b & 0xff)}, 0, 1);
}

/**
* {@inheritDoc}
*
* @since 1.1
*/
@Override
public void write(byte[] buffer) throws IOException {
write(buffer, 0, buffer.length);
}

/**
* {@inheritDoc}
*
* @since 1.1
*/
@Override
public void write(byte[] buffer, int offset, int length) throws IOException {
if (deflater.finished()) {
throw new IOException("Cannot write more data, the end of the compressed data stream has been reached");

} else if (length > 0) {
deflater.setInput(buffer, offset, length);

while (!deflater.needsInput()) {
deflate();
}

crc.update(buffer, offset, length);
}
}

private void deflate() throws IOException {
int length = deflater.deflate(deflateBuffer, 0, deflateBuffer.length);
if (length > 0) {

byte[] defByte = Arrays.copyOfRange(deflateBuffer, 0, length);

appendCompressedByte(defByte);

//out.write(defByte);
}
}

private void writeTrailer() throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.putInt((int) crc.getValue());
buffer.putInt(deflater.getTotalIn());

byte[] traByte = buffer.array();

appendCompressedByte(traByte);
//out.write(traByte);
}

/**
* Finishes writing compressed data to the underlying stream without closing it.
*
* @since 1.7
*/
public void finish() throws IOException {
if (!deflater.finished()) {
deflater.finish();

while (!deflater.finished()) {
deflate();
}

writeTrailer();
}
}

@Override
public void close() throws IOException {
if (!closed) {
finish();
deflater.end();
//out.close();
closed = true;
}
}

/**
* 追加压缩后的数组
* @param append
*/
public void appendCompressedByte(byte[] append){
int originalLength = compressedByte.length;
int appendLength = append.length;
//先扩容长度
int totalLength = originalLength + appendLength;

compressedByte = Arrays.copyOf(compressedByte, totalLength);

System.arraycopy(append, 0, compressedByte, originalLength, appendLength);

}

}

使用方法:

/**
* 文件压缩
*/
public static void copyTest(){
String pathFrom = "D:/testFile/compress/compress.txt";

String pathTo = "D:/testFile/compress/compress.txt.gz";

try {

GzipParameters parameters = new GzipParameters();

parameters.setFilename("test");
parameters.setCompressionLevel(5);

InputStream input = new FileInputStream(pathFrom);
OutputStream output = new FileOutputStream(pathTo);

GzipByteUtil gzipOut = new GzipByteUtil(parameters);

byte[] readByte = new byte[1024 * 4];

int length;
while((length = input.read(readByte)) != -1){
gzipOut.write(readByte, 0, length);

gzipOut.flush();
}

gzipOut.close();

//获取压缩二进制
byte[] resultByte = gzipOut.getCompressedByte();

output.write(resultByte);

System.out.println(resultByte.length);

output.close();
input.close();

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java gzip 内存 压缩