I have an excel template file I am retrieving from minIO, I perform some writing operation on this excel and I finally return the modified file to the user calling my code.
This flow was working fine until I tried to clone one of the sheet of my excel.
When I do that and I try to open it with Excel the file looks to be corrupted and Excel won't open it.
I am a bit lost, I am not sure what could cause this behaviour. I tried to clone an empty sheet I created for testing and it was working, so it might be related to the content of the sheet I am trying to clone but I have no idea as everything runs fine in the code.
So, theses are the part I consider relevants (getting the file from minIO, the moment I clone the sheet and finally when I write to a ByteArray)
try (InputStream inputStream = minioClient.getObject(
GetObjectArgs.builder()
.bucket("someBucket")
.object("someObject.xlsx")
.build()
)) {
Workbook workbook = new XSSFWorkbook(inputStream);
...
Sheet newSheet = workbook.cloneSheet(workbook.getSheetIndex(sheetTemplate));
workbook.setSheetName(workbook.getSheetIndex(newSheet.getSheetName()), "newName");
workbook.setSheetOrder("newName", workbook.getSheetIndex(sheetTemplate));
newSheet.getRow(10).getCell(2).setCellValue("someValue");
...
ByteArrayOutputStream bos = new ByteArrayOutputStream();
workbook.write(bos);
workbook.close();
return Optional.of(bos.toByteArray());
}
I know the question is pretty vague but maybe there is something in the way I handle this flow that it's incorrect although everything worked fine before I tried to clone some of the sheet of our template.
Any pointer would be highly appreciated.
Thank you in advance.
Related
I currently create xls files by outputting an HTML table with the proper header and file extension. Here is the sample code:
String tabledata = "<table>MORE TABLE HTML HERE</table>";
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\"somefile.xls\"");
out.println(tabledata);
This works great except you get an error before opening "The file format and extension of 'somefile.xls' don't match." Once opened, it looks exactly how I want it.
I used Apache POI elsewhere, so figured I could try using this, but I don't want to have to build all elements in some long script looking for rows, columns and different styles. I was thinking that I could convert the HTML to an InputStream and then create the Workbook, but it doesn't like the headers. Here is the code:
InputStream is = new ByteArrayInputStream(tabledata.getBytes("UTF-8"));
HSSFWorkbook wb = new HSSFWorkbook(is);
FileOutputStream fileOut = new FileOutputStream("somefile.xls");
wb.write(fileOut);
fileOut.close();
Is something like this possible if the headers were added/changed? If so, how would I modify this code to work properly?
I have a program that does various tasks and then logs the results to an excel file. I'm using Apache POI.
The program is working perfectly and is logging everything as I want it. However, it can take hours to complete, and I noticed that if I open the excel file while it's still running, it fails and throws a java.io.FileNotFoundException exception with this message (The process cannot access the file because it is being used by another process) when it tries to save to the file.
My guess is that by opening the excel file, the program is getting locked out of writing to it. How can I get around this? Is there a way to lock users out of opening the file while the program runs (Forcing them to access it as read-only)?
This is the code that gets used to initially create the file:
HSSFWorkbook wb = new HSSFWorkbook();
//.. bunch of POI stuff here
FileOutputStream fileOut = new FileOutputStream("C:\\ file path here");
wb.write(fileOut);
wb.close();
fileOut.close();
And then in a separate logResults() method, the file is accessed and saved:
FileInputStream file = new FileInputStream(new File("C:\\ file path here"));
HSSFWorkbook wb = new HSSFWorkbook(file);
//.. bunch more POI stuff here
FileOutputStream fileOut = new FileOutputStream("C:\\ file path here");
wb.write(fileOut);
wb.close();
fileOut.close();
I don't think you can do anything in Java side.
You may need do something in Excel file as follows
Private Sub Workbook_Open()
If ThisWorkbook.ReadOnly
Then
MsgBox "File already in use"
ThisWorkbook.Close
savechanges:=False
End If
End Sub
'This is workbook event code.
'To input this code, right click on the Excel icon on the worksheet
'(or next to the File menu if you maximise your workbooks),
'select View Code from the menu, and paste the code
I found a work around. I'm not sure if it's the most elegant solution, but it seems to work well enough.
When the file is created, I set it to read only with. Then every time I will log a result, I switch it back to writeable, and then back to read only after it's saved.
Basically something like this:
File file = new File(filePath);
//..
file.setWritable(true);
FileOutputStream fileOut = new FileOutputStream(filePath);
file.setReadOnly();
I want to edit an existing Excel file with Java, to add some more data to an existing template excel file. So i used Jexcel for this purpose.
As suggested everywhere, I tried the following,
Workbook existingWorkbook = Workbook.getWorkbook(new File("H://"+file_name));
WritableWorkbook copy = Workbook.createWorkbook(new File("H://"+file_name+"_temp1.xls"));
But it shows an exception in the second line.
jxl.common.AssertionFailed
at jxl.common.Assert.verify(Assert.java:37)
at jxl.read.biff.SheetReader.handleObjectRecord(SheetReader.java:1811)
at jxl.read.biff.SheetReader.read(SheetReader.java:1059)
at jxl.read.biff.SheetImpl.readSheet(SheetImpl.java:716)
at jxl.read.biff.WorkbookParser.getSheet(WorkbookParser.java:257)
at jxl.write.biff.WritableWorkbookImpl.copyWorkbook(WritableWorkbookImpl.java:969)
at jxl.write.biff.WritableWorkbookImpl.<init>(WritableWorkbookImpl.java:343)
at jxl.Workbook.createWorkbook(Workbook.java:339)
at jxl.Workbook.createWorkbook(Workbook.java:320)
at run_book.process_input.<init>(process_input.java:83) <--create workbook stt.
.........<stack trace goes on>
So how could one edit an already existing jexcel file.
I did get another warning
Warning: Text Object on sheet "sheet2" not supported - omitting
Thanks in advance :)
Figured out the problem.
We have to close the input file before writing back (editing) the same file.
so to edit an existing Excel file with Jexcel
File inp = new File("H://"+file_name);
File out = new File("H://"+file_name);
Workbook existingWorkbook = Workbook.getWorkbook(inp);// This opens up a read-only copy of the workbook
WritableWorkbook copy = Workbook.createWorkbook(out,existingWorkbook); // This opens up a writable workbook so that we can edit the copy
//..........Some writes to excel workbook...........
// Now before writing & closing the copy, first close the existing one
existingWorkbook.close(); // Important: Close it before writing the copy with copy.write();
inp.close();
copy.write();
copy.close();
I ran into this same issue and to solve the problem I updated to the latest version of jxl.jar via maven. After doing this there was a very long delay when it ran destinationWorkbook = Workbook.createWorkbook(outputFile, sourceWorkbook); but it completed successfully without errors.
I used a simple code from online code and I was able to call the method in the code in a for loop and passing it data and row number. The file is created properly, the file's size (after refreshing my file explorer) is changed upon each insert but when i am done I open the file and I can only see the first row in there and the moment i close it the size of the file decreases from 1.5MB to 5bytes. I opened the 1.5 MB file in notepadd++ (ofcourse it opened with byte characters) I could actually see the data that i have been writing into the file besides the first row, All my rows were there. but when i open in excel it doesnt.
Is there some thing I am missing here. At each insert into the excel file I am doing this :
fileOutputStream = new FileOutputStream(fileName,true);
sampleWorkbook.write(fileOutputStream);
and after that in the finally block of the try block :
finally {
/**
* Close the fileOutputStream.
*/
try {
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
but if the file size is changing and I can view the data in a notepad why is excel treating the rows other than the first one as temporary data (that is what I'm assuming it's doing as it reverts back to only 5 bytes when I close the file)? What's wrong here?
Thanks for your help, in advance.
syed.
The problem here is that xls isn't a simple format and adding a row into a xls doesn't mean appending several bytes in the end of the file. The new data is inserted in the middle of the file so you have to completely rewrite the whole file.
You code sample just writes another workbook after already existing workbook, which makes file content invalid. So when you open it in Excel it automatically corrects file content removing all added data except the first workbook.
Use this code sample:
InputStream in = new FileInputStream (path);
Workbook sampleWorkbook;
try{
sampleWorkbook = new HSSFWorkbook (in);//or XSSFWorkbook depending on whether you use xls or xlsx
} finally
{
in.close ();
}
//Add some rows into the workbook
OutputStream out = new FileOutputStream (path);
try{
sampleWorkbook.write (out);
} finally
{
out.close ();
}
Might not that relevant to your question, but for easy Excel generating, it's recommended to use JXLS (http://jxls.sourceforge.net/) which is built on top of POI. The beautiful part of JXLS is it enable you to create an Excel template (using Excel of course), and then you just put the data into the template. It supports basic logic operation including if else and loop.
If you can afford commercial solution take a look at Templater. It's very easy to use. Disclaimer: I'm the author.
Here is what I'm doing :
Create a workbook in memory (book = new HSSFWorkbook(), ...)
Save it to disk (book.write(...))
Open in Excel (ok)
Create another workbook in Excel, which links to the first one (=PoiWorkbook?xls!A1)
Close Excel
Then everytime I open the second workbook again, all the links are #N/A, unless I also open the POI-generated workbook at the same time.
I never saw this behaviour with standard workbooks created in Excel.
Anyone has seen this and found a workaround ?
Thanks.
This issue seems to be solved by newer version of POI (using 3.6 right now).