为什么Apache POI OPCPackage的close()方法不能保存/写入内容来打开可写文件?

使用下面的代码,不会保存对Excel电子表格所做的单元格值更改:

OPCPackage pkg = OPCPackage.open(inputFile); XSSFWorkbook wb = new XSSFWorkbook(pkg); ModifyWorkbook(); pkg.close(); 

以下是我写的解决方法,但我不明白为什么这是必要的。

 OPCPackage pkg = OPCPackage.open(inputFile); XSSFWorkbook wb = new XSSFWorkbook(pkg); ModifyWorkbook(); File tmp = File.createTempFile("tempSpreadsheet", ".xlsx"); FileOutputStream newExcelFile = new FileOutputStream(tmp); wb.write(newExcelFile); newExcelFile.close(); tmp.deleteOnExit(); pkg.close(); 

关于主题的javadoc和指南指出.close()方法应该保存并closures。 在closures之前,检查已修改的单元格的值,表明已作出更改,但单独使用pkg.close()方法不足以在closures时将这些更改写入文件。

调用OPCPackage.close()将closures底层的OOXML文件结构。 它不会做的是导致XSSF(或任何X ?? F格式)写出他们的变化。 所以,你会写出一个未更改的文件….

如果您正在进行低级修改,您可以打开OPCPackage,进行更改,然后调用close来写出它们。 如果你在做高层次的事情,你打开OPCPackage,使用UserModel代码进行修改,然后用户模型写出它的变化。 这是最重要的最后一步。

你目前的代码有点像:

 File f = new File("test.txt"); Sting s = readFileCompletely(f); s = s.replaceAll("foo", "bar"); f.close(); // Why hasn't the file contents changed? 

读取文件并修改高级对象是不够的,还需要告诉高级对象写出更改。 (由于性能原因,高级对象将内存caching在内存中)

调用(XSSF)工作簿close将调用OPCP.close javadoc指出:

调用myWorkbook.close()应该将更改写入文件。

然而,目前的版本(3.15)似乎有这样做的问题。 原因本身对我来说是未知的,但是我发现调用myWorkbook.write()将不仅会提交输出stream的更改,还会在调用close之后提交到​​当前实例。

因此,一个合理的解决方法是:

 try (OutputStream bos = ByteStreams.nullOutputStream()){ workbook.write(bos); workbook.close(); } catch (IOException e) { log.error("Could not write Output File", e); } 

这里用Guavas ByteStreams完成。 随意使用其他空输出stream的实现。