用zipoutputstream打包下载zip需设置响应头为application/zip和attachment;中文名用urlencoder编码;路径用正斜杠;空目录加"/";jdk7+推荐ziparchiveoutputstream并setencoding("utf-8")。

用 ZipOutputStream 将多个零散文件打包成 ZIP 并提供下载,核心是构造 ZIP 条目(ZipEntry),逐个写入文件内容,最后通过 HTTP 响应流输出字节。关键在于正确设置响应头、避免中文乱码、处理路径和空目录等细节。
设置响应头与输出流
确保浏览器识别为 ZIP 文件并触发下载:
- Content-Type 设为
application/zip - Content-Disposition 设为
attachment; filename="xxx.zip",注意中文文件名需用URLEncoder.encode()编码(如 UTF-8),部分老浏览器需兼容filename*=UTF-8''...格式 - 禁用缓存:
response.setHeader("Cache-Control", "no-store, no-cache") - 获取
ServletOutputStream或OutputStream,传给ZipOutputStream
逐个添加文件到 ZIP 流
每个文件对应一个 ZipEntry,路径需规范(用正斜杠 /,不能含盘符或绝对路径):
- 对普通文件:创建
ZipEntry(entryName),entryName 是 ZIP 内的相对路径,如"docs/report.pdf"或"img/logo.png" - 对空目录:创建
ZipEntry(dirName + "/")(末尾加斜杠),并调用putNextEntry(),不写入内容 - 调用
zos.putNextEntry(entry)后,用Files.copy(file, zos)或手动IOUtils.copy(in, zos)写入内容 - 每次写完必须调用
zos.closeEntry(),否则 ZIP 结构损坏
处理中文路径与文件名乱码
ZipOutputStream 默认使用 IBM437 编码,中文会乱码。解决方案:
- JDK 7+ 推荐用
java.util.zip.ZipOutputStream配合org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream(来自 commons-compress),它支持设置编码:zos.setEncoding("UTF-8") - 若坚持用原生类,可改用
new ZipOutputStream(new FileOutputStream(...), StandardCharsets.UTF_8)(JDK 11+ 支持) - 服务端生成的 entryName 若含中文,务必统一用 UTF-8 构造;前端下载时,Chrome/Firefox 基本支持,IE 需额外处理(如转拼音)
完整流程示例(Spring MVC 风格)
以 Controller 方法为例:
- 接收待打包的文件路径列表(如
List<string> filePaths</string>) - 设置响应头,获取
response.getOutputStream() - 初始化
ZipArchiveOutputStream,调用setEncoding("UTF-8") - 遍历每个路径:
File file = new File(path);计算 ZIP 内部名称(去除公共父目录,避免冗余层级);创建ZipArchiveEntry;如果是目录且为空,设entry.setDirectory(true);调用zos.putArchiveEntry(entry);如有内容则Files.copy(file.toPath(), zos);再zos.closeArchiveEntry() - 最后
zos.finish()和response.getOutputStream().flush()
不复杂但容易忽略编码和 closeEntry 的时机,建议封装工具方法复用。










