在web开发过程中,进行文件的压缩传输是一种常见的需求。比如一种场景:用户需要下载定时生成的报表,我们需要先对报表文件进行压以方便用户的下载,并减少文件的存储空间。
事实上,JDK已经提供了文件压缩/解压缩的支持,可以生成zip/gzip的压缩格式,并且支持支持“校验和”以检查压缩文件的完整性。通常会使用CRC(循环冗余校验)算法进行校验。
遗憾的是,JDK的文件压缩功能无法处理文件名称包含中文的问题。为此,我们需要用到ant.jar第三方开源支持包。
如下所示代码,采用Junit 4进行压缩功能的测试:
/*
* Copyright (c) 2014, hello_nick_xu@foxmail.com, All rights reserved.
*/
package com.test.zip;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.junit.Test;
/**
* 功能简述: 进行文件压缩功能测试
* @author Nick Xu
*/
public class ZipTest {
//源文件夹
private final String sourceDirStr = "E:/source";
//目标文件
private final String zipPath = "E:/dest.zip";
//缓冲区大小设置
private static final int BUFFER_SIZE = 1024;
/**
* 功能简述: 普通压缩测试
* @throws Exception
*/
@Test
public void testZip() throws Exception {
// zip输出流:使用缓冲流进行了包装
ZipOutputStream zipOut = new ZipOutputStream(
new BufferedOutputStream(
new FileOutputStream(zipPath), BUFFER_SIZE));
// 得到源文件夹下的文件列表
File sourceDirectory = new File(sourceDirStr);
File[] files = sourceDirectory.listFiles();
byte[] bs = new byte[BUFFER_SIZE]; // 缓冲数组
int value = -1; //文件是否结束标记
for (File file : files) { // 遍历所有的文件
zipOut.putNextEntry(new ZipEntry(file.getName())); // 存入文件名称,便于解压缩
//文件读写
BufferedInputStream bfInput = new BufferedInputStream(
new FileInputStream(file), BUFFER_SIZE);
while ((value = bfInput.read(bs, 0, bs.length)) != -1) {
zipOut.write(bs, 0, value);
}
bfInput.close(); //关闭缓冲输入流
}
//关闭输出流
zipOut.flush();
zipOut.close();
}
/**
* 功能简述: 文件压缩测试,获取校验和
* @throws Exception
*/
@Test
public void testZipWithCheckSum() throws Exception {
//被校验的输出流:使用CRC32校验算法
CheckedOutputStream checkedOutput = new
CheckedOutputStream(new BufferedOutputStream(
new FileOutputStream(zipPath), BUFFER_SIZE),new
CRC32());
//使用ZipOutputStream进行包装
ZipOutputStream zipOut = new ZipOutputStream(checkedOutput);
// 得到文件名称列表
File sourceDirectory = new File(sourceDirStr);
File[] files = sourceDirectory.listFiles();
// 读写文件
byte[] bs = new byte[BUFFER_SIZE];
int value = -1;
for (File file : files) {
BufferedInputStream bfInput = new BufferedInputStream(
new FileInputStream(file), BUFFER_SIZE);
zipOut.putNextEntry(new ZipEntry(file.getName()));
while ((value = bfInput.read(bs, 0, bs.length)) != -1) {
zipOut.write(bs, 0, value);
}
bfInput.close();
}
zipOut.flush();
zipOut.close();
//获取校验和:用于校验文件的完整性
long checkSum = checkedOutput.getChecksum().getValue();
System.out.println("checkSum : " + checkSum);
}
}
完整项目功能,参见附件