使用ZipOutputStream实现web端批量下载文件到浏览器
1、需求场景
平时我们开发web应用时可能会遇到用户在界面选择下载多个报表,点击下载按钮后需要批量下载这些文件到浏览器。但是一般情况下,页面一次点击只能触发一个文件的下载,所以无法实现上述诉求。
2、解决方案
针对上述的问题我们可以借助java.util.zip.ZipOutputStream这个类来实现该功能,具体的我们可以使用该类将多个报表文件压缩到一个zip包中,然后将这个zip包写回到浏览器。
3、代码实现
3.1、zip压缩代码
/** * * @param files 需要压缩的文件列表 * @param zipFile 压缩后的文件 */ public static void ZipMultiFile(List<File> files, File zipFile) { try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) { for (File file : files) { try (FileInputStream fis = new FileInputStream(file);) { zipOut.putNextEntry(new ZipEntry(file.getName())); int temp; byte[] buf = new byte[1024]; while ((temp = fis.read(buf)) != -1) { zipOut.write(buf, 0, temp); } zipOut.closeEntry(); zipOut.flush(); } catch (Exception ex) { ex.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } }
3.2、zip压缩文件写回浏览器代码
/** * 多文件下载 * @param files * @param zipFile * @param response */ public static void multiDownload(List<File> files, File zipFile, HttpServletResponse response) { response.reset(); // 设置response的Header response.setCharacterEncoding("UTF-8"); //Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存 //attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3" // filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称 try { response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipFile.getName(), "UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } // 告知浏览器文件的大小 //设置响应格式,已文件流的方式返回给前端。 response.setContentType("application/octet-stream"); //生成压缩文件 ZipMultiFile(files, zipFile); response.addHeader("Content-Length", String.valueOf(zipFile.length())); try (ServletOutputStream sos = response.getOutputStream(); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(zipFile))) { byte[] buff = new byte[1024 * 10]; int index; while ((index = bis.read(buff, 0, buff.length)) != -1) { sos.write(buff, 0, index); } sos.flush(); } catch (Exception e) { e.printStackTrace(); } }