数据库Blob转字节文件打包Zip下载无效问题求助
问题
将文件存储在数据库Blob中,无本地路径,读取为字节数据后,使用如下代码生成Zip文件供下载时,文件大小不为0KB,但生成的Zip文件无效,打开时提示“压缩文件已损坏或者格式未知”。
原代码如下:
@RequestMapping(value = "/downloadMultipleFilesAsZip", method = RequestMethod.POST) public void downloadMultiAsZip(@RequestParam("selectedFile[]") int[] selectedFiles, HttpServletRequest request, HttpServletResponse response) throws FileNotFoundException, IOException { List<FileUpload> fileToDownload = new ArrayList<FileUpload>(); System.out.println("=================================================="); for (int i = 0; i<selectedFiles.length; i++) { System.out.println("Value of multipleFile["+i+"] is " + selectedFiles[i]); FileUpload fu = new FileUpload(); fu.setFile_id(selectedFiles[i]); fileToDownload.add(fu); System.out.println("fileToDownload file_id is " + fileToDownload.get(i).getFile_id()); } // store details of downloads into fileToDownload fileToDownload = fuMapper.downloadMultipleAsZip(fileToDownload); //Do download OutputStream os = null; try { response.setContentType("application/zip"); response.setHeader("Content-Disposition", "attachment; filename=download.zip"); os = response.getOutputStream(); ZipOutputStream zos = new ZipOutputStream(os); System.out.println("================== Starting zip =================="); for(FileUpload fu : fileToDownload) { System.out.println("Zipping " + fu.getFile_name() + "....."); ZipEntry zipEntry = new ZipEntry(fu.getFile_name()); os.write(fu.getFile_data()); zos.finish(); zos.putNextEntry(zipEntry); zos.closeEntry(); } System.out.println("================== Finish zipping. =================="); os.flush(); zos.close(); os.close(); } catch (Exception e) { e.printStackTrace(); } }
问题排查与修复
你的代码存在几个关键错误,直接导致Zip文件损坏:
- 写入字节的对象错误:直接往原始输出流
os写文件字节,而非ZipOutputStream zos,字节未经过Zip格式封装就输出,破坏了Zip结构。 zos.finish()调用时机错误:该方法是所有Zip条目写完后才调用的收尾方法,你在循环里每次处理文件就调用,会提前终止Zip写入流程,后续条目无法正确添加。- ZipEntry操作顺序颠倒:正确流程是先创建Zip条目,再写入文件字节,最后关闭条目,你的代码顺序完全错乱。
修复后的代码如下:
@RequestMapping(value = "/downloadMultipleFilesAsZip", method = RequestMethod.POST) public void downloadMultiAsZip(@RequestParam("selectedFile[]") int[] selectedFiles, HttpServletRequest request, HttpServletResponse response) throws IOException { List<FileUpload> fileToDownload = new ArrayList<>(); for (int fileId : selectedFiles) { FileUpload fu = new FileUpload(); fu.setFile_id(fileId); fileToDownload.add(fu); } // 从数据库获取文件数据 fileToDownload = fuMapper.downloadMultipleAsZip(fileToDownload); response.setContentType("application/zip"); response.setHeader("Content-Disposition", "attachment; filename=download.zip"); // 使用try-with-resources自动管理流,避免资源泄漏 try (OutputStream os = response.getOutputStream(); ZipOutputStream zos = new ZipOutputStream(os)) { System.out.println("================== Starting zip =================="); for(FileUpload fu : fileToDownload) { System.out.println("Zipping " + fu.getFile_name() + "....."); ZipEntry zipEntry = new ZipEntry(fu.getFile_name()); zos.putNextEntry(zipEntry); // 先创建当前文件的Zip条目 zos.write(fu.getFile_data()); // 往Zip流写入文件字节 zos.closeEntry(); // 关闭当前条目 } System.out.println("================== Finish zipping. =================="); zos.finish(); // 所有条目处理完成后,结束Zip写入流程 os.flush(); } catch (Exception e) { e.printStackTrace(); // 错误时返回500状态码,方便前端感知异常 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } }
额外优化说明:
- 用
try-with-resources语法自动关闭流,避免手动关闭可能引发的异常或资源泄漏。 - 简化了
selectedFiles的遍历代码,逻辑更清晰。 - 添加了异常时的响应状态码设置,完善错误处理逻辑。
内容的提问来源于stack exchange,提问作者Luffyyy
相关产品推荐
相关产品推荐

