本文是对前面写的《Java实现压缩解压文件》进行了问题修复与功能补充。
老版本在实现上面有些问题,在通过addFile像压缩包中添加文件时,一旦前面的addFile添加文件失败,就会导致接下来所有的addFile都无法成功。原先的方法实现为:
public ZipObject addFile(byte[] fileBytes, String fileName) {
try {
// 可以理解一个ZipEntry就表示压缩包里面的一个文件
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
zos.write(fileBytes, 0, fileBytes.length);
} catch (IOException e) {
e.printStackTrace();
if (bos!=null) {
try {
bos.close();
} catch (IOException ee){}
}
if (zos!=null) {
try {
zos.close();
} catch (IOException ee){}
}
}
return this;
}
上述原因是因为在异常捕获catch代码块中的bos.close()与zos.close()将文件流关闭了,这样在后续继续调用addFile时就会出现报错了。因此,不需要关闭文件流。改造后的方法为:
public ZipObject addFile(byte[] fileBytes, String fileName) {
try {
// 可以理解一个ZipEntry就表示压缩包里面的一个文件
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
zos.write(fileBytes, 0, fileBytes.length);
} catch (IOException e) {
e.printStackTrace();
}
return this;
}
(1)在实际使用中,我们经常遇到的文件有很多是Excel,Word文档等。比如会使用org.apache.poi.ss.usermodel.Workbook来生成Excel文件。当与Workbook结合我们的ZipUtil如何来使用呢,代码如下:(因为addFile只提供了一个byte[]类型的参数,因此我们需要先将Workbook内容写到ByteArrayOutputStream,再通过ByteArrayOutputStream获取字节数组)
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
workbook.write(byteArrayOutputStream);
zipObject.addFile(byteArrayOutputStream.toByteArray(), "示例.xls");
为了简化该操作,我们重载一个方法:
public ZipObject addFile(ByteArrayOutputStream outputStream, String fileName) {
return addFile(outputStream.toByteArray(), fileName);
}
(2)在实际使用中,我们经常需要将压缩包文件响应给浏览器进行下载。比如结合HttpServletResponse将内容响应给浏览器。代码如下:
OutputStream outputStream = response.getOutputStream();
response.setHeader("Content-Disposition", "attachment;filename=file.zip");
response.setContentType("application/octet-stream;charset=UTF-8");
outputStream.write(zipObject.create());
为了简化该操作,我们重载一个方法:
public void write(OutputStream outputStream) {
try {
outputStream.write(create());
} catch (Exception e) {
e.printStackTrace();
}
}
更可以用参数将HttpServletResponse接受,将响应浏览器功能的代码封装到方法中。
附上改造之后完整的代码:
public class ZipUtil {
private ZipUtil() {
throw new RuntimeException("Illegal operation");
}
// 压缩文件
public static ZipObject createZipObject() {
return new ZipObject();
}
// 解压文件,参数是压缩文件字节数组
public static UnZipObject createUnZipObject(byte[] bytes) {
if (bytes==null || bytes.length==0) {
throw new IllegalArgumentException("bytes is null");
}
return new UnZipObject(bytes);
}
public static class ZipObject {
// 工具流
private ZipOutputStream zos;
// 使用带有缓冲功能的文件流存储文件
private ByteArrayOutputStream bos;
private ZipObject() {
bos = new ByteArrayOutputStream();
// 文件数据流实际存储在了bos
zos = new ZipOutputStream(bos);
}
/**
* 添加一个文件到压缩包中
* @param fileBytes 文件的字节数组
* @param fileName 文件名,带文件类型的,比如:hello.xlsx
* @return
*/
public ZipObject addFile(byte[] fileBytes, String fileName) {
try {
// 可以理解一个ZipEntry就表示压缩包里面的一个文件
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
zos.write(fileBytes, 0, fileBytes.length);
} catch (IOException e) {
e.printStackTrace();
}
return this;
}
/**
* 结合文件流,比如 Workbook.write();
* @param outputStream
* @param fileName
* @return
*/
public ZipObject addFile(ByteArrayOutputStream outputStream, String fileName) {
return addFile(outputStream.toByteArray(), fileName);
}
/**
* 生成压缩包的字节数组
* @return
*/
public byte[] create() {
byte[] bytes = null;
try {
// 将数据写到ByteArrayOutputStream中
zos.finish();
bytes = bos.toByteArray();
bos.flush();
zos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos!=null) {
try {
bos.close();
} catch (IOException e){}
}
if (zos!=null) {
try {
zos.close();
} catch (IOException e){}
}
}
return bytes;
}
/**
* 结合Spring框架的HttpServletResponse response响应出去
* zipObject.write(response.getOutputStream());
* @param outputStream
*/
public void write(OutputStream outputStream) {
try {
outputStream.write(create());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static class UnZipObject {
// 工具流
private ZipInputStream zis;
// 使用带有缓冲功能的文件流存储文件
private ByteArrayInputStream bis;
private int size;
private UnZipObject(byte[] bytes) {
size = bytes.length;
bis = new ByteArrayInputStream(bytes);
// 文件数据流实际存储在了bos
zis = new ZipInputStream(bis);
}
/**
* 获取压缩包里面的文件,一个ZipEntry表示一个文件
* @return
*/
public List getEntrys() {
List list = new ArrayList<>();
try {
ZipEntry nextEntry = zis.getNextEntry();
// 一个个循环读取压缩文件中的内容,放进bytes数组中
while (nextEntry!=null) {
byte[] bytes = new byte[size];
zis.read(bytes);
nextEntry.setExtra(bytes);
list.add(nextEntry);
nextEntry = zis.getNextEntry();
}
} catch (IOException e) {
e.printStackTrace();
if (bis!=null) {
try {
bis.close();
} catch (IOException ee){}
}
if (zis!=null) {
try {
zis.close();
} catch (IOException ee){}
}
}
return list;
}
}
}