如何在Spring Boot中通过REST API实现目录压缩功能?
错误原因
你代码报错的核心原因是FileInputStream仅支持读取普通文件,无法直接读取目录对象。你传入的C:\\Pavan\\zipfolder是目录路径,直接构造FileInputStream就会触发FileNotFoundException。
可运行的Spring Boot实现代码
依赖说明(可选)
如果使用Apache Commons IO做流复制,先在pom.xml引入依赖:
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>
不需要额外依赖的话可以自己实现流复制逻辑,下方代码会标注替换位置。
完整Controller代码
import org.apache.commons.io.IOUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @RestController public class ZipController { // 替换为你要压缩的根目录路径 private static final String ROOT_ZIP_PATH = "C:\\Pavan\\zipfolder"; @RequestMapping(value = "/zip", produces = "application/zip") public void zipDirectory(HttpServletResponse response) throws IOException { response.setStatus(HttpServletResponse.SC_OK); response.addHeader("Content-Disposition", "attachment; filename=\"compressedfile.zip\""); // try-with-resources会自动关闭流,无需手动处理资源释放 try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) { File rootFile = new File(ROOT_ZIP_PATH); // 递归添加目录下所有文件到压缩包 addFileToZip(rootFile, rootFile.getName(), zipOutputStream); } } /** * 递归添加文件/目录到压缩包 * @param file 当前处理的文件/目录对象 * @param entryName 压缩包内的路径,用于保留原目录层级 * @param zipOutputStream 压缩输出流 * @throws IOException IO异常 */ private void addFileToZip(File file, String entryName, ZipOutputStream zipOutputStream) throws IOException { if (file.isDirectory()) { // 处理目录:末尾加/标识为目录,空目录也会正常写入压缩包 String dirEntryName = entryName.endsWith("/") ? entryName : entryName + "/"; zipOutputStream.putNextEntry(new ZipEntry(dirEntryName)); zipOutputStream.closeEntry(); // 遍历子文件递归处理 File[] childFiles = file.listFiles(); if (childFiles != null) { for (File childFile : childFiles) { addFileToZip(childFile, dirEntryName + childFile.getName(), zipOutputStream); } } return; } // 处理普通文件 zipOutputStream.putNextEntry(new ZipEntry(entryName)); try (FileInputStream fis = new FileInputStream(file)) { // 不用commons-io的话,把下面这行替换为注释里的代码即可 IOUtils.copy(fis, zipOutputStream); /* 无依赖的流复制代码 byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) > 0) { zipOutputStream.write(buffer, 0, len); } */ } zipOutputStream.closeEntry(); } }
注意事项
- 代码会完整保留原目录的层级结构,压缩包内的文件路径和本地目录结构完全一致
- 支持空目录、多层嵌套目录的压缩
- 部署到Linux环境时只需要把
ROOT_ZIP_PATH改为对应Linux路径即可,无需修改其他逻辑
内容的提问来源于stack exchange,提问作者Prathish
相关产品推荐
相关产品推荐

