项目场景
项目上需要将多个文件压缩成一个压缩包下载
问题描述
下载下来的压缩包用360压缩解压可以解压成功(但是如果压缩文件的最后是一个空文件夹的话,解压出来不是一个空文件夹,而是一个识别不出来文件格式的文件)
用WinRAR解压失败
原因分析
字节输出流和压缩输出流的关闭顺序问题,压缩输出流未将完整数据流输出到字节输出流,字节输出流即被关闭
解决方案
public ResponseEntity<byte[]> fileBatchDownLoad(...) {
...
//字节数组输出流构造
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//压缩输出流在字节数组输出流的基础上构造
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);
List<InputStream> inputStreamList = ... //获取输入流
for (int i = 0; i < inputStreamList.size(); i++) {
InputStream inputStream = inputStreamList.get(i);
byte[] buffer = new byte[1024];
int len;
ZipEntry entry = new ZipEntry(fileNames.get(i));
try (BufferedInputStream in = new BufferedInputStream(inputStream)) {
//获取需要下载的文件流
zipOutputStream.putNextEntry(entry);
//文件流循环写入ZipOutputStream
while ((len = in.read(buffer)) != -1) {
zipOutputStream.write(buffer, 0, len);
}
inputStream.close();
zipOutputStream.closeEntry();
} catch (Exception e) {
e.printStackTrace();
}
}
try {
//先关闭压缩输出流,再关闭字节数组输出流,否则生成的压缩文件解压会出错,
//虽然360压缩有时候能解压,但是使用WinRAR解压就一定会出错(先构造的后关闭)
zipOutputStream.close();
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (StringUtils.isEmpty(zipName)) {
zipName = "数据";
}
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", new String((zipName + ".zip").getBytes(), StandardCharsets.ISO_8859_1));
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<>(byteArrayOutputStream.toByteArray(), headers, HttpStatus.OK);
}