18

I constructed a new Workbook using WorkbookFactory.create(new File("path/to/xlsx")). However, when I try to edit the File in Excel after starting the application, I get an error message that the file is in use. Do I have to free the file up, and if so, how? (I could not find anything like Workbook.close() in the api docs) Or do I have to look in other places?

I have no clue where else to look; the application does not cause these issues with csv and for excel files I simply call the converter (xls => csv) which is the only difference.

(I am using POI 3.8)

Simulant
  • 19,190
  • 8
  • 63
  • 98
ted
  • 4,791
  • 5
  • 38
  • 84

6 Answers6

18

It seems to work just fine to maintain a handle on the InputStream passed to WorkbookFactory.create(), and to simply close the InputStream when you're done with the Workbook. For example:

    InputStream is = // initialize
    try {
        Workbook wb = WorkbookFactory.create(is);
        // use the workbook
    } finally {
        if (is != null) is.close()
    }
Mark T.
  • 447
  • 4
  • 14
  • 4
    Nice one. If you know you will perform read-only operations, you can also close the InputStream as soon as the workbook has been created, as it then sits in memory. I personally find it more explicit. – Arnaud P Jul 01 '13 at 20:47
  • 2
    What about closing wb ? – gstackoverflow Sep 25 '17 at 08:46
  • @ArnaudP Are you sure about that? I tried that and got a defective file. And it contradicts Gagravarr's comment to his answer. – JosefScript Mar 02 '18 at 11:00
  • @JosefScript it was a long time ago, I added this comment because it worked in my case, but I'm certainly not an expert on that matter. I'd be tempted to delete it for safety, but it has 4 votes, so I dunno. – Arnaud P Mar 02 '18 at 16:54
13

If you need full control of when the resources get closed, you should create the OPCPackage yourself up front, and pass that into WorkbookFactory. OPCPackage provides the close method you're after. A Workbook will remain open until garbage collection

Your code would look something like:

     File f = new File("/path/to/excel/file");
     Workbook wb = null;

     NPOIFSFileSystem npoifs = null;
     OPCPackage pkg = null;
     try {
       npoifs = new NPOIFSFileSystem(f);
       wb = WorkbookFactory.create(npoifs);
     } catch(OfficeXmlFileException ofe) {
       pkg = OPCPackage.open(f);
       wb = WorkbookFactory.create(pkg);
     }

     // Use it

     if (npoifs != null) { npoifs.close(); }
     if (pkg != null) { pkg.close(); }
Gagravarr
  • 47,320
  • 10
  • 111
  • 156
  • 1
    thank you, I will give it a shot. Why doesn't Workbook.create release the file pointer? My shallow understanding is that File objects are not filepointers, since you can't do IO on them. Thus I assume that `Workbook.create` does open the file for IO, why can't it close it as well, if it opened it? (I take it you have insights on the topic, just a wild guess but you work on POI?) – ted Sep 04 '12 at 13:12
  • I tested it and it works like a charm. Thanks a bunch. I took the freedom to edit your awnser. Is there any reason why you keep the _file_ open while working on the _workbook_? – ted Sep 04 '12 at 13:53
  • The file is kept open so that when you write out changes to a new stream, the other bits of the file (eg embedded resources) can be streamed out too – Gagravarr Sep 04 '12 at 14:50
  • Ok, and what was wrong with leveraging the power of `Workbook.create` to differentiate between xls/xlsx? Why did you remove that part as well? (I might repost it as a sepearte awnser if there is nothing wrong with it, no worries yours will stay the accepted awnser) – ted Sep 04 '12 at 15:37
  • If you want full control over the closing of the resources, you need to control the wrapping of the file into an open object. If you don't mind when things get automatically closed, or you shift to a unix system, then `Workbook.create(File)` should do you just fine! – Gagravarr Sep 05 '12 at 08:53
  • Is it necessary to catch the OfficeXmlFileException exception? Because I omitted that part in my code fix and everything worked fine. – ohseekay Jun 02 '14 at 06:37
  • If you pass an OOXML file (eg .xlsx) to NPOIFSFileSystem, it'll throw an `OfficeXmlFileException` to let you know it's the wrong kind of file – Gagravarr Jun 02 '14 at 08:23
  • >> A Workbook will remain open until garbage collection Would the file handles be released after garbage collection ? If yes how does it work ? Is there some finalize method which releases the file handle? – Abhijeet Jul 13 '17 at 10:36
2

How to close an instance of a POI workbook in Java:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;


try{
    File workbookFile = new File("C:\\repo\\yourfile.xslx");
    FileInputStream file = new FileInputStream(workbookFile);
    Workbook wb = WorkbookFactory.create(file);
    Sheet sheet = wb.getSheetAt(0);

    //use the instance of wb.

    file.close();

}
catch(Exception e){
    System.out.println("Fail");
}
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
  • 3
    That doesn't seem to close the Workbook, only the underlying stream. Also, it's higher memory than using a File object, see the [POI documentation on the topic](http://poi.apache.org/spreadsheet/quick-guide.html#FileInputStream) – Gagravarr Nov 23 '14 at 09:54
2

First you need to close the stream which is written to the workBook:

workBook.write(outputStream);

outputStream.close();

After that u should close the workBook (for no further operations) and dispose the temporary files:

//Close the workBook
workBook.close();

//deleting the temporary files
workBook.dispose();
André Kool
  • 4,880
  • 12
  • 34
  • 44
Yaniv
  • 21
  • 3
1

I am using poi api version 5.0.0. The Workbook in this version has a close() method which as per the API document says:

"Close the underlying input resource (File or Stream),from which the Workbook was read."

//Using try-catch-finally:

Workbook workbook = null;
try {
    workbook = WorkbookFactory.create(inputStream);
    //....
} catch (IOException ex) {
    //...
}finally {
    workbook.close();
}

//Using try-with-resources:

try(Workbook workbook = WorkbookFactory.create(fileStream)) {
    //....
} catch (IOException ex) {
    //...
}
0

Just suffer from the same problem, as of 2021. :(, when using poi version 3.9.

I just find that if we upgrade the poi version to 3.17 (in case you are still using Java 7, which poi version 4 or above only Support Java 8 or above),

Then the Workbook will implement AutoCloseable.

Therefore one can use Try-With-Resources block to auto close the File.

Here is the demo code.

try (Workbook workbook = WorkbookFactory.create(new File(fileLocation))) {
   // operate on the workbook here...
}

Which I think the above code is better than @Gagravarr solution, as it is copying what the create method do outside, which developer not familiar with poi library does not know what is it.


P.S. Indeed this question is placed in bugzilla as a bug, see https://bz.apache.org/bugzilla/show_bug.cgi?id=56537, and is resolved and the code is merged in poi 3.11 or later. Therefore anyone having the same issue as we do, can have a look at it, and close the resources when finish using it.

CHANist
  • 1,302
  • 11
  • 36