需求:同时下载多个文件,并将它们放入一个压缩文件中。
废话不多说,直接上代码。
/**
* 批量下载压缩附件
* @param attachMap key为附件path,value为附件名
* @param zipFileName 压缩文件名
* @param response 响应
* @throws Exception
*/
public void download(Map<String, String> attachMap, String zipFileName, HttpServletResponse response) throws Exception {
if (response == null) {
throw new Exception("请求异常!");
}
if (attachMap == null || attachMap.isEmpty()) {
throw new Exception("下载附件不能为空!");
}
response.setContentType("application/octet-stream;charset=utf-8");
//设置编码,避免返回的中文名乱码
response.addHeader( "Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipFileName, "UTF-8"));
try {
byte[] buffer = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream fos = new BufferedOutputStream(baos);
ZipOutputStream zos = new ZipOutputStream(fos);
List<String> filenames = new ArrayList<>();
for (String filepath : attachMap.keySet()) {
File file = new File(filepath);
InputStream fis = new FileInputStream(file);
//解决压缩包内文件名重复问题
String filename = attachMap.get(filepath);
while(filenames.contains(filename)){
String _filename = filename.substring(0, filename.lastIndexOf(".")) + "(1)";
String typename = filename.substring(filename.lastIndexOf("."));
filename = _filename + typename;
}
filenames.add(filename);
//压缩文件内的文件名称
zos.putNextEntry(new ZipEntry(filename));
int length;
while ((length = fis.read(buffer)) > 0) {
//将文件读入压缩文件内
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
}
zos.close();
fos.flush();
try (
OutputStream _os = response.getOutputStream();
InputStream is = new ByteArrayInputStream(baos.toByteArray());
) {
byte[] buffer1 = new byte[1024 * 5];
int len = 0;
while ((len = is.read(buffer1)) > 0) {
_os.write(buffer1, 0, len);
}
_os.flush();
} catch (IOException e) {
throw new Exception("下载异常: {}", e);
}
} catch (Exception e) {
e.printStackTrace();
}
}
此方法中有两点需要注意:一是对压缩文件名的转码处理,没有此步骤会导致下载的压缩件中文名乱码;二是对各个附件名的重复性判断,因为同一个压缩件内是不允许文件重名的,否则会导致下载异常!