SXSSFWorkbook 无法写入数据,文档似乎已经关闭

Posted

技术标签:

【中文标题】SXSSFWorkbook 无法写入数据,文档似乎已经关闭【英文标题】:SXSSFWorkbook Cannot write data, document seems to have been closed already 【发布时间】:2021-10-25 16:34:19 【问题描述】:

我在将数据写入 SXSSFWorkbook 文件时遇到异常。我可以使用 XSSFWorkbook 做同样的事情,而且效果很好。

java.io.IOException: Cannot write data, document seems to have been closed already
at org.apache.poi.ooxml.POIXMLDocument.write(POIXMLDocument.java:230)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.write(SXSSFWorkbook.java:953)
at org.glassfish.jersey.message.internal.StreamingOutputProvider.writeTo(StreamingOutputProvider.java:79)
at org.glassfish.jersey.message.internal.StreamingOutputProvider.writeTo(StreamingOutputProvider.java:61)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:266)

这是我的代码。

public static Response createResponseUsingStreaming() throws IOException 
    SXSSFWorkbook workbook = report.generateStreamingExcelReport(100);
    StreamingOutput outputStream = workbook::write;
    final String contentType = "application/vnd.ms-excel";

    Response.ResponseBuilder responseBuilder = Response.ok(outputStream);
    responseBuilder.header("Content-Disposition", "attachment; filename=test");
    responseBuilder.header("Access-Control-Expose-Headers", "Content-Disposition");
    responseBuilder.header("Content-Type", contentType);
    Response response = responseBuilder.build();
    if (null != workbook) 
        workbook.dispose();
        workbook.close();
    
    return response;


public SXSSFWorkbook generateStreamingExcelReport(int rowAccessWindowSize) 
    List<List<String>> rows = createRawData();
    SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(rowAccessWindowSize);

    createExcelSummaryPage(sxssfWorkbook);
    createExcelDetailPage(rows, sxssfWorkbook);

    return sxssfWorkbook;

在创建新的 SXSSFWorkbook 时设置了 OPCPackage,想知道在哪里设置为 null。

public final void write(OutputStream stream) throws IOException 
    OPCPackage p = getPackage();
    if(p == null) 
        throw new IOException("Cannot write data, document seems to have been closed already");
    

    //force all children to commit their changes into the underlying OOXML Package
    // TODO Shouldn't they be committing to the new one instead?
    Set<PackagePart> context = new HashSet<>();
    onSave(context);
    context.clear();

    //save extended and custom properties
    getProperties().commit();

    p.save(stream);

【问题讨论】:

您是否检查过createExcelSummaryPagecreateExcelDetailPage 是否正在关闭工作簿?否则,ResponseResponse.ResponseBuilder 到底是什么?如果这些是异步的,那么当responseBuilder.build() 调用workbook::write 时,工作簿可能已经关闭。 否,createExcelSummaryPage 或 createExcelDetailPage 没有关闭工作簿。我正在使用 REST API 下载报告,而 Response 和 Response.ResponseBuilder 是我用来构建响应的 javax 库。 所以ResponseResponse.ResponseBuilderjavax.ws.rs.core.*-classes?然后我建议标记java-ee 以吸引Java EE 用户回答这个问题。因为我没有使用Java EE,所以我无能为力。 【参考方案1】:

如果您可以使用XSSFWorkbook,您应该可以使用您的XSSFWorkbook 使用SXSSFWorkbook

这是一个简单的工作示例:

public void createExcelFileUsingSXSSFWorkbook(XSSFWorkbook wb) 

    SXSSFWorkbook wbSXSSF = new SXSSFWorkbook(wb);

    try 
        Path path = Files.createFile(Path.of("test.xlsx"));
        try (OutputStream outputStream = Files.newOutputStream(path)) 
            wbSXSSF.write(outputStream);
            wbSXSSF.close();
         catch (IOException e2) 
            e2.printStackTrace();
        
     catch (IOException e1) 
        e1.printStackTrace();
    


【讨论】:

【参考方案2】:

我能够按以下方式解决此问题

outputStream = outputStream1 -> 
            sxssfWorkbook.write(outputStream1);
            sxssfWorkbook.dispose();
            sxssfWorkbook.close();
        ;

工作簿正在写入 responseBuilder.build(),所以我必须将 write()、dispose() 和 close() 烘焙到输出流中才能正常工作

【讨论】:

以上是关于SXSSFWorkbook 无法写入数据,文档似乎已经关闭的主要内容,如果未能解决你的问题,请参考以下文章

利用POI操作Excel实现百万数据写入

HSSFWorkbook-SXSSFWorkbook导出excel文件获取大小记录

java excel poi 中的SXSSFWorkbook wb = new SXSSFWorkbook(workbook, 1000);是啥意思?

poi的XSSFWorkbook转SXSSFWorkbook发现的问题

《JAVA》编程中怎么用SXSSFWorkbook对已存在的excel操作进行写数据操作

poi导出大数据,报内存溢出怎么解决