正在阅读:
- 首页 » 开发运维 » 后端 » SpringBoot压缩多个文件后下载
SpringBoot压缩多个文件后下载
经常遇到需求,服务器要批量压缩一个或者多个文件,响应给客户端。这里演示一个Demo。
客户端通过参数指定服务器上的某个文件夹,服务器对该文件夹进行zip压缩后响应给客户端。
controller层代码:
import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.LinkedList; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller @RequestMapping("/download") public class DownloadController { @GetMapping public void download(HttpServletRequest request, HttpServletResponse response, @RequestParam("folder") String folder) throws UnsupportedEncodingException { Path folderPath = Paths.get(folder); if (!Files.isDirectory(folderPath)) { // 文件夹不存在 response.setStatus(HttpServletResponse.SC_NOT_FOUND); return ; } // 二进制数据流 response.setContentType("application/octet-stream"); // 附件形式打开 response.setHeader("Content-Disposition", "attachment; filename=" + new String((folderPath.getFileName().toString() + ".zip").getBytes("GBK"),"ISO-8859-1")); try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())){ LinkedList<String> path = new LinkedList<>(); Files.walkFileTree(folderPath, new FileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { // 开始遍历目录 if (!dir.equals(folderPath)) { path.addLast(dir.getFileName().toString()); // 写入目录 ZipEntry zipEntry = new ZipEntry(path.stream().collect(Collectors.joining("/", "", "/"))); try { zipOutputStream.putNextEntry(zipEntry); zipOutputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // 开始遍历文件 try (InputStream inputStream = Files.newInputStream(file)) { // 创建一个压缩项,指定名称 String fileName = path.size() > 0 ? path.stream().collect(Collectors.joining("/", "", "")) + "/" + file.getFileName().toString() : file.getFileName().toString(); ZipEntry zipEntry = new ZipEntry(fileName); // 添加到压缩流 zipOutputStream.putNextEntry(zipEntry); // 写入数据 int len = 0; // 10kb缓冲区 byte[] buffer = new byte[1024 * 10]; while ((len = inputStream.read(buffer)) > 0) { zipOutputStream.write(buffer, 0, len); } zipOutputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { // 结束遍历目录 if (!path.isEmpty()) { path.removeLast(); } return FileVisitResult.CONTINUE; } }); zipOutputStream.closeEntry(); } catch (IOException e) { e.printStackTrace(); } } }
演示
下载本地磁盘的 D:\\Nginx 目录,注意文件路径参数有特殊符号,需要进行uri编码。
http://localhost/download?folder=D%3a%5c%5cnginx-1.18.0
对比原始文件夹和下载后解压开来的文件夹,大小一致说明没问题。
该日志由 bemender 于 2020年10月26日 发表
转载请注明文本地址:https://www.bemhome.com/post/48.html