Why won't Apache POI OPCPackage close() method save/write contents to open writable file?

DanielReid picture DanielReid · Apr 19, 2013 · Viewed 7.6k times · Source

Using the following code, cell value changes made to my Excel Spreadsheet are not saved:

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

ModifyWorkbook();

pkg.close();

The following is a workaround I wrote, but I don't understand why it's necessary.

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();

The javadocs and guides on the subject indicate that the .close() method should save and close. Checks on the values of the cells modified, prior to closing, indicate that the changes ARE made, but the pkg.close() method alone is not sufficient to write those changes to the file when closed.

Answer

Gagravarr picture Gagravarr · Apr 19, 2013

A call to OPCPackage.close() will close the underlying OOXML file structure. What it won't do is cause XSSF (or any of the X??F formats) to write their changes out. So, you'll write out an un-changed file....

If you're doing low level modifications, you can open the OPCPackage, make changes, then call close to write them out. If you're doing high level stuff, you open the OPCPackage, work with the UserModel code to make changes, then ask the usermodel to write out its changes. It's this last step that's important.

Your current code is somewhat like:

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

Reading the file in and modifying the high level objects isn't enough, you also need to tell the high level objects to write out the changes. (The high level objects cache things in memory for performance reasons)