对于压缩包的导出处理,我们一般会使用到三种流的操作
第一种:
// 字节数组输出流,用于返回压缩后的输出流字节数组
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ByteArrayOutputStream 是一个输出流,数据写入其中会存储在内存中的字节数组中。
它的主要作用就是将传入的数据存储在一个内部的字节数组中,能够动态扩展这个字节数组以容纳更多的数据。
第二种:
// ZIP压缩输出流
ZipOutputStream zip = new ZipOutputStream(byteOut);
ZipOutputStream 是一个专门用于 ZIP 文件格式的输出流,它可以将多个文件/数据条目压缩并写入到底层输出流中。
ZipOutputStream 使用底层输出流(在这种情况下是 ByteArrayOutputStream)实际就是存储压缩后的数据。
当你创建 ZipOutputStream 时,将 ByteArrayOutputStream 作为参数传递给它:
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(byteOut);
此时,ZipOutputStream 持有对 ByteArrayOutputStream 的引用,所有写入 ZipOutputStream 的数据最终都会通过 write() 方法传递给 ByteArrayOutputStream。
第三种:
// Servlet输出流
OutputStream servletOut = response.getOutputStream();
ZipOutputStream 和 ByteArrayOutputStream 的关系
ZipOutputStream 是一个专门用于 ZIP 文件格式的输出流,它可以将多个文件/数据条目压缩并写入到底层输出流中。
ZipOutputStream 使用底层输出流(在这种情况下是 ByteArrayOutputStream)实际就是存储压缩后的数据。
当你创建 ZipOutputStream 时,将 ByteArrayOutputStream 作为参数传递给它:
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(byteOut);
此时,ZipOutputStream 持有对 ByteArrayOutputStream 的引用,所有写入 ZipOutputStream 的数据最终都会通过 w
1.ByteArrayOutputStream和ZipOutputStream可以结合使用来将数据压缩为 ZIP 格式并写入到内存中的 byte 数组中。
ByteArrayOutputStream 用于将数据写入 byte 数组,而 ZipOutputStream 则用于将数据压缩为 ZIP 格式。
2.可以使用 zip.putNextEntry(new ZipEntry("test/订单" + i + ".xlsx")); 指定单条目录的名称
putNextEntry代表单个条目数据,ZipEntry 用来指定信息
3.写入信息一般都会有一个叫 write 类的方法,比如 poi的XSSFWorkbook类
把 XSSFWorkbook 的信息写入一个字节数组输出流中 ByteArrayOutputStream 就使用 XSSFWorkbook.write(ByteArrayOutputStream);
XSSFWorkbook 的数据就会被写入到 ByteArrayOutputStream 字节数组中
4.把字节数组输出流中的数据,写入zip 中
bos 就是一个独立的 ByteArrayOutputStream ,应为压缩包中的每个条目就是一个 ByteArrayOutputStream
bos.writeTo(zip);
通过 bos.writeTo(zip) 我们单条的数据就已经被写入到了 ZIP压缩输出流中。
写入成功以后需要 zip.flush() 一下,这样可以 刷新压缩输出流 ,
最后我们关闭当前这个条目,让流定位写入下一个条目 zip.closeEntry()。
这样单条目数据就都处理完毕。
5.关闭流
当单条数据写入完毕以后,ByteArrayOutputStream 就完成了使命,需要关闭他,
这里可以使用 IOUtils.closeQuietly(bos),来关闭他。
6.总结
当所有条目处理完毕以后,我们需要关闭当前的 zip 流
IOUtils.closeQuietly(zip); 这里需要注意一下:(转换byte[]前必须关闭zip流。)
byte[] data = byteOut.toByteArray(); 转为字节数组
然后通过 HttpServletResponse.reset() 清除缓冲区数据。
此时我们就可以 通过 HttpServletResponse 获取 Servlet输出流,把 byte[] data 的数据写入到 OutputStream 中了
OutputStream servletOut = response.getOutputStream();
这里可以使用 IOUtils 工具类的 write 方法 IOUtils.write(data, servletOut)。 把ZIP字节数组写入到Servlet输出流
最后在关闭 ByteArrayOutputStream 字节数组输出流 以及 OutputStream Servlet输出流,这时我们就形成看完整的闭环。
IOUtils.closeQuietly(byteOut);
IOUtils.closeQuietly(servletOut);
7.关于压缩包信息设置
在 response 中我们可以设置下载方式,文件名称
response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".zip");
设置文件下载总大小,前端可以通过这个显示下载进度条
response.addHeader("Content-Length", "" + data.length);
内容的内容类型及编码格式:application/octet-stream[二进制流]
response.setContentType("application/octet-stream; charset=UTF-8");
以及设置文件名称编码格式
fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
PS:这就完事了...
还有一点,如果下载下来的压缩包是损坏的格式,那么可能是由于 流的关闭顺序不对导致的。