java.io.IOException: Stream closed的问题排查

tech2023-02-15  96

最近开发“导出数据生成文件”功能时使用到多处OutputStream流操作。

如导出excel文件:

//创建outputStream response.setContentType("APPLICATION/OCTET-STREAM"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipName.concat(".zip"), "UTF-8")); outputStream = response.getOutputStream(); //写入 wb.write(outputStream); outputStream.flush();

如导出zip文件:

//创建zipOutputStream public static void setZipOutputStream(HttpServletResponse response, String zipName) throws IOException { response.setContentType("APPLICATION/OCTET-STREAM"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipName.concat(".zip"), "UTF-8")); outputStream = new ZipOutputStream(response.getOutputStream()); } //excel压缩到zip public static void excelToZipEntry(SXSSFWorkbook workbook, String excelName) throws IOException { File tmpFile = TempFile.createTempFile("poi-sxssf-template", ".xlsx"); boolean deleted; try (FileOutputStream os = new FileOutputStream(tmpFile); FileInputStream fileInputStream = new FileInputStream(tmpFile); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream)) { workbook.write(os); ZipEntry entry = new ZipEntry(excelName + ".xlsx"); outputStream.putNextEntry(entry); byte[] buffer = new byte[1024]; int len; while ((len = bufferedInputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } } finally { outputStream.closeEntry(); deleted = tmpFile.delete(); if (!deleted) { throw new IOException("Could not delete temporary file after processing: " + tmpFile); } } } //压缩pdf到zip public static void pdfToZipEntry(String pdfFileName, byte[] bytes) throws IOException { try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes)) { ZipEntry entry = new ZipEntry(pdfFileName + ".pdf"); outputStream.putNextEntry(entry); byte[] buffer = new byte[1024]; int len; while ((len = byteArrayInputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } } finally { outputStream.closeEntry(); } }

经常会遇到的异常就是:

java.io.IOException: Stream closed

原因在于: 每次往流里写数据的源代码里,都会检查一下流是否关闭,关闭就抛 java.io.IOException: Stream closed

虽然知道这个异常的意思,但是在找关闭outputstream的原因的时候,还是花费了一些时间。

例如: 在ZipFileUtil是一个生成zip文件的工具类。 ZipFileUtil.class里创建了一个全局唯一的OutputStream,但是在创建的时候,却使用了如下方式创建:

public class ZipFileUtil { private static ZipOutputStream outputStream; private static File file; public static void setZipOutputStream(String filePath) { file = new File(filePath); try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { outputStream = new ZipOutputStream(fileOutputStream); } catch (Exception e) { log.error("创建ZipOutputStream失败,filePath={}", filePath, e); } outputStream = new ZipOutputStream(fileOutputStream); } }

try-catch的方式创建流,在try-catch代码结束的时候会自动关闭OutputStream,

所以在后续插入数据的时候,直接抛出了java.io.IOException: Stream closed

修改方案:

public static void setZipOutputStream(String filePath) { file = new File(filePath); try { fileOutputStream = new FileOutputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } outputStream = new ZipOutputStream(fileOutputStream); }
最新回复(0)