Bug 56745 - POIXMLException raised when saving workbook if workbook is opened with XSSFWorkbook(String) constructor
Summary: POIXMLException raised when saving workbook if workbook is opened with XSSFWo...
Status: RESOLVED LATER
Alias: None
Product: POI
Classification: Unclassified
Component: XSSF (show other bugs)
Version: 3.10-FINAL
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: POI Developers List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-07-18 23:53 UTC by Javen O'Neal
Modified: 2015-02-10 15:58 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Javen O'Neal 2014-07-18 23:53:43 UTC
I am getting the following exception when trying to write my workbook out to a file:

org.apache.poi.POIXMLException: java.io.IOException: Can't obtain the input stream from /docProps/app.xml

Here's the code to reproduce the problem (my best translation from Jython to Java)
// open workbook
    String filename = "C:\\path\\to\\file.xlsx";
    File file = new File(filename);
    Workbook wb = new XSSFWorkbook(filename);

    // save the workbook to disk
    FileOutputStream out = new FileOutputStream(file);
    wb.write(out);
    out.close();

The error occurs while writing the file (wb.write(out)).

Additionally, after XSSFWorkbook(filename) has run, if I try to rename the file in Windows Explorer, I get a "File In Use: The application can't be completed because the file is open in Java(TM) Platform SE binary". I'm not sure if this is a related problem.

The following code does not have this problem:
    // open workbook
    FileInputStream in = new FileInputStream(file);
    wb = WorkbookFactory.create(file);
    in.close();

    // save the workbook to disk
    FileOutputStream out = new FileOutputStream(file);
    wb.write(out);
    out.close();

Related: bug #56537. Does the fix for 56537 also fix this bug?
Comment 1 Nick Burch 2014-07-19 08:15:40 UTC
Can you try with a recent svn checkout / nightly build + adding a Workbook.close() call?
Comment 2 Javen O'Neal 2014-07-21 20:55:33 UTC
Using POI 3.11 nightly (2014-07-21), I get the same behavior as 3.10-FINAL.

    // open workbook
    String filename = "C:\\path\\to\\New Microsoft Excel Worksheet.xlsx";
    Workbook wb = new XSSFWorkbook(filename);

    // save workbook
    File file = new File(filename);  // output and input filename are the same
    FileOutputStream out = new FileOutputStream(file);
    wb.write(out);
    out.close();
    wb.close();

raises the following while trying to write to the FileOutputStream
Traceback (most recent call last):
  File "<input>", line 1, in <module>
POIXMLException: org.apache.poi.POIXMLException: java.io.IOException: Can't obtain the input stream from /docProps/app.xml

It appears that if I read the file unbuffered (either via String or File), the file becomes write protected after calling XSSFWorkbook(String) or XSSFWorkbook(File). The only way to release the write protection after running the above code is to kill the application.

Closing the workbook after reading it frees up the write protection (so the file can be renamed in Windows Explorer or edited in another application), however it causes a problem when trying to write the workbook.

    // open workbook
    String inFilename = "C:\\path\\to\\New Microsoft Excel Worksheet.xlsx";
    Workbook wb = new XSSFWorkbook(inFilename);
    wb.close();
    int sheetCount = wb.getNumberOfSheets(); //returns 3

    // save workbook
    String outFilename = "C:\\path\\to\\output.xlsx";
    File file = new File(outFilename);
    FileOutputStream out = new FileOutputStream(file);
    wb.write(out);
    out.close();
    wb.close();

raises the following exception while trying to write to the FileOutputStream.
Traceback (most recent call last):
  File "<input>", line 1, in <module>
OpenXML4JRuntimeException: org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException: Rule M2.4 exception : this error should NEVER happen, if so please send a mail to the developers team, thanks !

It seems like the solution for this is to not read and write to the same file (or at least while the workbook hasn't been closed). Maybe this was my misunderstanding of the POI API, but it's possible there's something broken that I've discovered. The problem with this code is that I must keep the file locked for access from XSSFWorkbook(inFilename) to wb.close().

    // open workbook
    String inFilename = "C:\\path\\to\\New Microsoft Excel Worksheet.xlsx";
    wb = XSSFWorkbook(inFilename);

    // save workbook
    String outFilename = "C:\\path\\to\\output.xlsx";
    File file = new File(outFilename);
    FileOutputStream out = new FileOutputStream(file);
    wb.write(out);
    out.close();
    wb.close();
Comment 3 Javen O'Neal 2014-07-21 20:58:39 UTC
Correction: no wb.close() after out.close() on the 2nd code example of comment #2. The workbook was already closed after XSSFWorkbook(inFilename).
Comment 4 Nick Burch 2014-07-21 21:06:30 UTC
Try any other operating system other than Windows, and it should work just fine...

The underlying OpenXML code supports in-place write, but XSSF does not, so your options are:
 * Use another OS
 * Write to a different file
 * Write a pile of code to allow XSSF to do an in-place update of the OPCPakcage

Historically, HSSF only supported writing to a new outputstream because POIFSFileSystem didn't support updating streams within the OLE2 structure. These days, the replacement NPOIFSFileSystem does support it, as does the OPC code, but no-one has been bothered to spend the not insignificant amount of time to update HSSF and XSSF to do in-place updates of streams within open packages
Comment 5 Dominik Stadler 2015-02-10 15:58:13 UTC
Based on the previous comments this is nothing that we plan to fix anytime soon unless someone can provide patches.