使用Apache POI修改现有的xlsx电子表格会导致无法读取的内容错误

时间:2016-01-22 19:22:28

标签: java excel apache-poi

因此,使用Apache POI的Excel中无法读取的内容错误主题似乎很常见。然而,我很惊讶我仍然找不到我的问题的一个例子,特别是因为我想要做的事情似乎非常简单。这让我相信一些东西可能只是我对一些java对象的理解,特别是File和FileInputStream。我通过大量的试验和错误发现了如何让它发挥作用,但我的问题是为什么一个有用,为什么另一个没有,并且想要了解潜在的问题。我认为也可以帮助其他人理解。这正是我想要做的:

打开现有的xlsx文件,向其中添加工作表,并将其保存为与原始文件相同的文件名。实质上,只需修改现有的xlsx文件即可添加工作表。

下面是不起作用的代码,以及执行的代码,我想知道为什么使用File对象不起作用。在这两个例子中,我已经创建了 TravelVouchers.xlsx 带有名为 Voucher_1 的工作表的文件,可以正常打开它。

以下代码导致travelVouchersWkBk.write(fileOut);行上的NullPointerException:

File travelVouchersFile = new File("./Output/TravelVouchers.xlsx");
Workbook travelVouchersWkBk = WorkbookFactory.create(travelVouchersFile);
travelVouchersWkBk.createSheet("Voucher_2");
FileOutputStream fileOut = new FileOutputStream(travelVouchersFile);
travelVouchersWkBk.write(fileOut);
fileOut.flush();
fileOut.close();

虽然以下代码效果很好:

File travelVouchersFile = new File("./Output/TravelVouchers.xlsx");
FileInputStream fileIn = new FileInputStream(travelVouchersFile);
Workbook travelVouchersWkBk = WorkbookFactory.create(fileIn);
travelVouchersWkBk.createSheet("Voucher_2");
fileIn.close();
FileOutputStream fileOut = new FileOutputStream(travelVouchersFile);
travelVouchersWkBk.write(fileOut);
fileOut.flush();
fileOut.close();

在不起作用的代码中,它会导致excel中出现无法读取内容的错误,当我选择修复时,我可以打开它,它只有Voucher_1。所以很明显使用带有File对象的WorkbookFactory.create不起作用,使用FileInputStream的情况不行,但我想知道我对File vs FileInputStream的理解与此问题有关。

非常感谢您的澄清,我真的很感激! 保罗

1 个答案:

答案 0 :(得分:3)

我相信使用FileWorkbookFactory阅读Workbook 然后写入相同 {{1} } - Workbook直到现在才是个好主意。 apache POI文档提到:

  

Files vs InputStreams

     

打开工作簿时,可以是.xls HSSFWorkbook,也可以是.xlsx   XSSFWorkbook,可以从文件或文件加载工作簿   的InputStream。使用File对象可以降低内存消耗,   而InputStream需要更多内存,因为它必须缓冲   整个文件。

为什么使用File对象可以降低内存消耗?这是因为File然后创建了一个Workbookfactory,它不需要在内存中完全读取。要验证,请阅读RandomAccessFile - >的来源WorkbookFactory.javapublic static Workbook create(File file, String password, boolean readOnly) - > NPOIFSFileSystem.javaprivate NPOIFSFileSystem(FileChannel channel, File srcFile, boolean readOnly, boolean closeChannelOnError) - > FileBackedDataSource.java

但据我所知,无法访问此private static RandomAccessFile newSrcFile(File file, String mode)。所以我们无法写信给它,也无法关闭它而不关闭整个RandomAccessFile。因此,在上面的示例中,Workbook将在RandomAccessFile尝试编写文件时打开以进行读写(rw模式)。

因此,使用Workbook.write(FileOutputStream)可能只适合阅读或从一个文件读取并保存到另一个文件。但是直到现在使用File来读取和写入同一个文件并不是一个好主意。对于此FileFileInputStream更好。