Java POI递归写入字符串数组至XLSX遇流关闭错误求助
递归写入SXSSFWorkbook触发Stream closed错误的解决方法
问题描述
尝试通过递归函数将字符串数组形式的ResultSet逐行写入XLSX文件,运行时抛出以下错误:
java.lang.RuntimeException: java.io.IOException: Stream closed
定位到错误源自workbook.write()方法,需要解决递归场景下的操作拆分问题。
初始代码
import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; public class XlsxService { private final Path outputFilePath; private SXSSFWorkbook workbook; private SXSSFSheet sheet; private Cell cell; private int rowNum = 0; public XlsxService(Path outputFilePath) { this.outputFilePath = outputFilePath; } public void generate(String[] resultSet) { if(workbook == null) { workbook = new SXSSFWorkbook(); sheet = workbook.createSheet("Sheet"); } writeToFile(resultSet); try (OutputStream fos = Files.newOutputStream(outputFilePath)) { workbook.write(fos); workbook.close(); } catch (IOException e) { throw new RuntimeException(e); } } public void writeToFile(String[] params) { Row dataRow = sheet.createRow(rowNum); for (int i = 0; i < params.length; i++) { dataRow.createCell(i).setCellValue(params[i]); } rowNum++; } }
更新后的代码
public void generate(String[] resultSet) { addRow(resultSet); save(); } public void save() throws IOException { try (OutputStream fos = Files.newOutputStream(outputFilePath)) { workbook.write(fos); } workbook.close(); } public void addRow(String[] params) { Row dataRow = sheet.createRow(rowNum); for (int i = 0; i < params.length; i++) { dataRow.createCell(i).setCellValue(params[i]); } rowNum++; }
ResultSet示例
String[] resultSet1 = {"A1", "B1", "C1"}; String[] resultSet2 = {"A2", "B2", "C2"}; ... String[] resultSetN = {"AN", "BN", "CN"};
错误原因
不管是初始还是更新后的代码,都犯了同一个核心错误:在递归过程中提前关闭了SXSSFWorkbook。
- 每次调用
generate都会执行save(),而save()里调用了workbook.close(),一旦workbook被关闭,后续递归调用时再操作workbook就会触发「流已关闭」的异常。 - SXSSFWorkbook的
write()方法本身不应该被多次调用(除非特殊配置),但最关键的问题是递归还未完成就释放了核心资源。
解决方法
拆分操作流程,将初始化、递归添加行、最终保存关闭三个环节彻底分离:
- 初始化workbook和sheet仅执行一次,避免递归中重复创建或判断。
- 递归函数只负责添加行数据,不涉及保存和资源释放。
- 所有递归执行完毕后,统一调用保存方法,一次性写入文件并关闭资源。
修改后的完整代码
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; public class XlsxService { private final Path outputFilePath; private SXSSFWorkbook workbook; private SXSSFSheet sheet; private int rowNum = 0; public XlsxService(Path outputFilePath) { this.outputFilePath = outputFilePath; // 初始化工作簿和工作表,仅执行一次 this.workbook = new SXSSFWorkbook(); this.sheet = workbook.createSheet("Sheet"); } // 递归处理行数据的入口方法,仅负责添加行 public void processRow(String[] resultSet) { addRow(resultSet); // 这里添加你的递归逻辑,比如判断是否还有下一行数据,示例省略终止条件 // if (hasNextResultSet()) { // processRow(getNextResultSet()); // } } // 所有行处理完成后,统一调用此方法完成写入和资源释放 public void finalizeAndSave() throws IOException { try (OutputStream fos = Files.newOutputStream(outputFilePath)) { workbook.write(fos); } finally { // 先关闭工作簿 workbook.close(); // 清理SXSSF生成的临时文件,避免资源泄漏 workbook.dispose(); } } // 内部方法:添加单行数据 private void addRow(String[] params) { Row dataRow = sheet.createRow(rowNum); for (int i = 0; i < params.length; i++) { dataRow.createCell(i).setCellValue(params[i]); } rowNum++; } }
使用示例
// 实例化服务 Path outputPath = Path.of("output.xlsx"); XlsxService xlsxService = new XlsxService(outputPath); // 模拟递归处理所有ResultSet(实际场景中替换为你的递归逻辑) xlsxService.processRow(new String[]{"A1", "B1", "C1"}); xlsxService.processRow(new String[]{"A2", "B2", "C2"}); xlsxService.processRow(new String[]{"A3", "B3", "C3"}); // 所有行处理完毕后,统一保存 xlsxService.finalizeAndSave();
关键注意点
- 递归过程中绝对不能关闭workbook或OutputStream,否则后续操作会触发流关闭异常。
- SXSSFWorkbook会生成临时文件来优化内存,务必调用
dispose()清理这些文件,防止磁盘空间泄漏。 - 初始化操作放在构造函数中,确保只执行一次,避免递归中重复创建资源。
内容的提问来源于stack exchange,提问作者3oJIoTou
相关产品推荐
相关产品推荐

