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)
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()
}
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(); }
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");
}
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();
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) {
//...
}
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.
Related
In this method i used xssf class which is used to read xlsx file but we cant do it for xls file.for xls we need to have Hssf class .User can import any format there .My requirement,Is there any Class that can be used instead of xssf and hssf to read both kind of file. in my example i used xssf.
#RequestMapping(value="/import",method = RequestMethod.POST)
public ModelAndView imports(Model model, #RequestParam("excelFile") MultipartFile excelfile){
try {
List<DepartmentModel> lstUser = new ArrayList<>();
int i = 0;
XSSFWorkbook workbook = new XSSFWorkbook(excelfile.getInputStream());
XSSFSheet worksheet = workbook.getSheetAt(0);
while (i <= worksheet.getLastRowNum()) {
DepartmentModel user = new DepartmentModel();
XSSFRow row = worksheet.getRow(i++);
user.setHrName(row.getCell(0).getStringCellValue());
user.setDepartmentName(row.getCell(1).getStringCellValue());
user.setParentDepartment(row.getCell(2).getStringCellValue());
lstUser.add(user);
}
departmentService.updateList(lstUser);
model.addAttribute("lstUser", lstUser);
} catch (Exception e) {
e.printStackTrace();
}
return new ModelAndView("redirect:/listOfDepartment");
}
Im having another method which i used Hssf to read xls file.But iam having only one import button user can upload any type of file xls,xlsx but for import button i can have one action eigther go to xssf or hssf method.So i like to know is there any possible way to have botth in single method.Or any other super class to having property of both Xssf and Hssf Class.
For supporting both HSSF as well as XSSF for reading and rewriting *.xls and *.xlsx, you will using WorkbookFactory for creating Workbook. This is able creating Workbook from InputStream of *.xls as well as of *.xlsx files.
FileInputStream fileinputstream = new FileInputStream("pathToExcelFile.xls_or_.xlsx");
Workbook workbook = WorkbookFactory.create(fileinputstream);
Then, as long as possible, you will working with the interfaces of Package org.apache.poi.ss.usermodel instead of the special HSSF or XSSF classes.
This is not always possible since apache poi is in development until now. But if not possible you can detect via instanceof what object (HSSF or XSSF) you really are working with.
And for writing you will using the appropriate methods dependent of the instanceof the Workbook.
if (workbook instanceof XSSFWorkbook) {
workbook.write(new FileOutputStream("pathToExcelFile.xlsx"));
} else if (workbook instanceof HSSFWorkbook) {
workbook.write(new FileOutputStream("pathToExcelFile.xls"));
}
workbook.close();
Up to apache poi 3.17 Workbook.write has closed the OutputStream. Now in apache poi 4.0.* versions it not more closes the OutputStream. So we need using
FileOutputStream out = null;
if (workbook instanceof XSSFWorkbook) out = new FileOutputStream("pathToExcelFile.xlsx");
else if (workbook instanceof HSSFWorkbook) out = new FileOutputStream("pathToExcelFile.xls");
if (out != null) {
workbook.write(out);
out.close();
}
workbook.close();
I am getting this error:
org.apache.poi.poifs.filesystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (e.g. XSSF instead of HSSF)
I read throw Google and I found out that I need to use XSSF instead of HSSF because my Excel file is xlsx, but as you see in my maven, I am already using xlsx. Where have I gone wrong please?
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.13-beta1</version>
</dependency>
The code the makes the exception is:
POIFSFileSystem fs;
fs = new POIFSFileSystem(new FileInputStream(getFilePath()));
My new code
public void getBColum() {
try {
OPCPackage fs;
fs = new OPCPackage.open(new File(getFilePath()));
XSSFWorkbook wb = new XSSFWorkbook(fs);
XSSFSheet sheet = wb.getSheet("Master column name - Used Car");
XSSFRow row;
CellReference cr = new CellReference("A1");
row = sheet.getRow(cr.getCol());
System.out.println(row.getCell(3));
} catch (FileNotFoundException e) {
if (logger.isDebugEnabled()) {
logger.debug("How can this error be possible? we should have already thrown an exception in the construction");
}
} catch (IOException e) {
logger.error(String.format("Exception in reading the file: %s",
e.getMessage()));
}
}
I have a compile error in new oPCPackage.open which is:
OPCPackage.open cannot be resolved to a type
According to the Apache POI Quick Guide, the POIFSFileSystem (or similarly, NPOIFSFileSystem) is only used with .xls (Excel versions through 2003) documents.
The equivalent for .xlsx documents (Excel 2007+) is OPCPackage.
OPCPackage pkg = OPCPackage.open(new File("file.xlsx"));
You can create an XSSFWorkbook from the OPCPackage:
XSSFWorkbook wb = new XSSFWorkbook(pkg);
Or you can just create it directly:
XSSFWorkbook wb = new XSSFWorkbook(new File("file.xlsx"));
Generally it's better to create the workbook using a File instead of an InputStream, to save memory.
Also, if you want code that doesn't care whether it's an .xls or an .xlsx:
// or "file.xlsx"
Workbook wb = WorkbookFactory.create(new File("MyExcel.xls"));
I was using XSSF with a xlsx file, but got this error when I tried to process a file that was encrypted/protected with a password.
Once I removed the password, everything worked as expected.
well actually there is no OPCPackage,
I am using https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml/3.5-beta5
so you have to:
import org.apache.poi.openxml4j.opc.Package;
....
Package fs = Package.open(new ByteArrayInputStream(container.getContent()));
XSSFWorkbook wb = new XSSFWorkbook(fs);
XSSFSheet sheet = wb.getSheetAt(0);
XSSFRow row;
XSSFCell cell;
While trying to open an excel using ApachePOI I get
org.apache.poi.openxml4j.exceptions.InvalidOperationException: Can't open the specified file: 'C:\Users\mdwaipay\AppData\Local\Temp\poifiles\poi-ooxml-1570030023.tmp'
I checked. No such folder is being created. I am using Apache POI version 3.6.
Any help? A similar code was running fine in a different workspace. At loss of thoughts here.
Code:
public Xls_Reader(String path) {
this.path=path;
try {
fis = new FileInputStream(path);
workbook = new XSSFWorkbook(fis);
sheet = workbook.getSheetAt(0);
fis.close();
}
catch (Exception e)
{ e.printStackTrace();
}
}
Why are you taking a perfectly good file, wrapping it in an InputStream, then asking POI to have to buffer the whole lot for you so it can do random access? Life is much better if you just pass the File to POI directly, so it can skip about as needed!
If you want to work with both XSSF (.xlsx) and HSSF (.xls), change your code to be
public Xls_Reader(String path) {
this.path = path;
try {
File f = new File(path);
workbook = WorkbookFactory.create(f);
sheet = workbook.getSheetAt(0);
} catch (Exception e) {
e.printStackTrace();
}
}
If you only want XSSF support, and/or you need full control of when the resources get closed, instead do something like
OPCPackage pkg = OPCPackage.open(path);
Workbook wb = new XSSFWorkbook(pkg);
// use the workbook
// When you no longer needed it, immediately close and release the file resources
pkg.close();
I am getting the following exception while trying to write an .xlsx file using Apache POI: org.apache.xmlbeans.impl.values.XmlValueDisconnectedException
It seems the problem is using the method write () second time.
When working with a HSSFWorkbook of this problem does not arise.
Here's the Code:
public class SomeClass{
XSSFWorkbook workbook;
public SomeClass() throws IOException{
File excelFile = new File("workbook.xlsx");
InputStream inp = new FileInputStream(excelFile);
workbook = new XSSFWorkbook(inp);
inp.close();
}
void method(int i) throws InvalidFormatException, IOException {
XSSFSheet sheet = workbook.getSheetAt(0);
XSSFRow row = sheet.getRow(i);
if (row == null) {
row = sheet.createRow(i);
}
XSSFCell cell = row.getCell(i);
if (cell == null)
cell = row.createCell(i);
cell.setCellType(Cell.CELL_TYPE_STRING);
cell.setCellValue("a test");
// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
workbook.write(fileOut);
fileOut.close();
}
public static void main(String[] args) throws Exception {
SomeClass sc = new SomeClass();
sc.method(1);
sc.method(2);
}
}
I've had the same problem today. I've noticed many people asking the same question on many different forums, but I haven't seen an answer anywhere. So, here is what I came up with. It is far from ideal (I can think of at least two scenarios where this might be a bad idea), and may not suite every need, but it works!
After every save operation inside the class which the workbook object is a property of, I reload the workbook from the file I just saved it to.
Using your code example above, I would modify the method like so:
void method(int i) throws InvalidFormatException, IOException {
...
// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
workbook.write(fileOut);
fileOut.close();
// Reload the workbook, workaround for bug 49940
// https://issues.apache.org/bugzilla/show_bug.cgi?id=49940
workbook = new XSSFWorkbook(new FileInputStream("workbook.xlsx"));
}
I tested this in my code, and it resolved the issue nicely. Just make sure that you read it back in from the same file you saved it to, and not an earlier or different version.
This is most likely a bug.
https://issues.apache.org/bugzilla/show_bug.cgi?id=49940
I suggest you subscribe to that ticket to get notified about current improvements / alternatives.
If I find a workaround I will let you know.
The solution I've found for this, and I've been looking for a while, is to make sure you don't open your Workbook with the File which you use to open the FileOutputStream to save the Workbook. Instead, use a FileInputStream to open the Workbook.
Something like this will work flawlessly
File inputFile = new File("Your-Path");
this.inputStream = new FileInputStream(inputFile);
this.opc = OPCPackage.open(this.inputStream);
this.workbook = WorkbookFactory.create(opc);
...
this.outputStream = new FileOutputStream(inputFile);
this.workbook.write(this,outputStream);
Don't forget to close every opened stream and the OPCPackage.
This occurs only when we try to write more than once to the same file that too for a .xlsx file. I came accross the same issue and got it resolved by..
Previously i was writing twice
Now removed the first write call
Passed the same workbook instance to the method and set values to the new cell
finally did some more changes to the workbook by writing few more columns and cells
Then wrote using the file output stream.
It was working
I too faced the same issue when using apache poi 3.10.
But after adding latest apache poi jar files, it worked for me.
Please try after updating the jars to latest.
I had the same problem too. Later, I tried another method and it solved.
In this case, we can move the code:
FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
workbook.write(fileOut);
fileOut.close();
out of the method(int i), and then in the main method, we can use:
sc.method(1);
sc.method(2);
FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
workbook.write(fileOut);
fileOut.close();
Then, the workbook.write is only used for once. Also the data could be modified several times.
This seems to be indeed a bug in XSSFSheet.createRow(int index). As long as the bug is not fixed, using this class as a workaround should do the trick :
import java.util.Iterator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
public class PoiHacks
{
// Fix of XSSFSheet.createRow(int index)
public static Row createRow(Sheet sheet, int index) {
Row row = sheet.getRow(index);
if(row==null) return sheet.createRow(index);
Iterator it = row.iterator();
while(it.hasNext()) {
it.next();
it.remove();
}
return row;
}
}
Use :
PoiHacks.createRow(sheet, 0);
I am trying to generate Excel reports using Apache POI 3.6 (latest).
Since POI has limited support for header and footer generation (text only), I decided to start from a blank excel file with the header already prepared and fill the Excel cells using POI (cf. question 714172).
Unfortunately, when opening the workbook with POI and writing it immediately to disk (without any cell manpulation), the header seems to be lost.
Here is the code I used to test this behavior:
public final class ExcelWorkbookCreator {
public static void main(String[] args) {
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(new File("dump.xls"));
InputStream inputStream = ExcelWorkbookCreator.class.getResourceAsStream("report_template.xls");
HSSFWorkbook workbook = new HSSFWorkbook(inputStream, true);
workbook.write(outputStream);
} catch (Exception exception) {
throw new RuntimeException(exception);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException exception) {
// Nothing much to do
}
}
}
}
}
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = new HSSFSheet();
Header header = sheet.getHeader() //get header from workbook's sheet
header.setCenter(HSSFHeader.font("COURIER", "Normal")+ HSSFHeader.fontSize((short) 15) + "Hello world" +new Date()); // set header with desire font style
FileOutputStream fileOut = new FileOutputStream("C:\\book.xls");
workbook.write(fileOut);
The headers of the Excel file are preserved as long as those headers are supported in Excel 97-2003. For example, images are supported (I just tried it), but colored text is not.
The tricky part of this is that your Excel template file "dump.xls" must be in Excel 97-2003 format. Please note: this is not the file extension, but the actual contents of the file. The newest Excel will happily save the newest formatting in a .xls file, which POI cannot read.
To test this, save your Excel file as an .xls file. Important - If you receive a compatibility warning, then you must click the "Correct" link in the dialog to correct the Excel. Just clicking Proceed makes the Excel file invalid to POI.
Once you have a real .xls file (with compatible contents) then your code works. I just tested it myself:
public static void main(String[] args) throws Exception {
try (FileInputStream fis = new FileInputStream("./report_template.xls");
FileOutputStream fos = new FileOutputStream("./dump.xls")) {
HSSFWorkbook wb = new HSSFWorkbook(fis);
wb.write(fos);
}
}