Upgrading from .xls to .xlsx with POI - java

I have a web application In which i have excel file(.xls) download option. Now I Have to provide that feature in .xlsx
I am trying to Use POI Jar. When I try to do that as a stand alone Application it works fine, but when I try to integrate that into a web application, I am getting an error as
Excel Found Unreadable Content in FILENAME.xlsx. do you want to recover the content of this workbook?
If you trust the source of this workbook click yes!
XSSFWorkbook w = FileName.createExcelWorkbookPosition(
request.getParameter("BSNS_DT"));
response.setContentType(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition","attachment;filename=filename.xlsx");
w.write(response.getOutputStream());
Here's the Java code where I create the spreadsheet:
public static XSSFWorkbook createExcelWorkbookPosition(String BsnsDate)
throws Exception
{
FileOutputStream out = new FileOutputStream("workbook.xlsx");
// create a new workbook
XSSFWorkbook wb = new XSSFWorkbook();
// create a new sheet
XSSFSheet s = wb.createSheet();
// declare a row object reference
XSSFRow r = null;
// declare a cell object reference
XSSFCell c = null;
// header row and columns
r = s.createRow(0);
c = r.createCell(0);
c.setCellValue("Business Date");
//c.setCellStyle(cs);
c = r.createCell(1);
c.setCellValue("Account No");
try {
wb.write(out);
out.close();
System.out.println("File writed");
} catch (Exception e) {
System.out.println("Error");
System.out.println(e);
}
return wb;
}
Can anyone please help? Sorry for any bad English! Thanks.

I had a quite similar issue, please have a look at Forcing the browser to download a docx file in JAVA generates a corrupted document. The point was to add the Content-Length header of the response.
Try to make createExcelWorkbookPosition returning the file instead of the XSSFWorkbook:
public static File createExcelWorkbookPosition(String BsnsDate) throws Exception {
File file = new File("workbook.xlsx");
FileOutputStream out = new FileOutputStream(file);
// ...
return file;
}
Then:
File file = FileName.createExcelWorkbookPosition(request.getParameter("BSNS_DT"));
// ...
response.setContentLength((int) file.length());
InputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
// if using Apache IO, the above code can be simplified to IOUtils.copy(in, out);
// if using Guava, Files.copy(file, out);
// don't forget to close your streams and flush the response buffer

Related

How to close XSSF file with out.close()?

I am trying to save and close an existing workbook that I am already successfully opening but for some reason cannot either save and close:
//declarations etc here...
try {
InputStream ExcelFileToRead = new FileInputStream(file);
XSSFWorkbook wb = new XSSFWorkbook(ExcelFileToRead);
//XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(new File(file)));
XSSFSheet sheet = wb.getSheetAt(0);
XSSFRow row;
XSSFCell cell;
int rows;
rows = sheet.getPhysicalNumberOfRows();
int cols = 1;
XSSFRichTextString path;
String stpath;
try {
if(!Desktop.isDesktopSupported()){
System.out.println("Error: Desktop is not supported");
}
Desktop desktop = Desktop.getDesktop();
if(filee.exists()) desktop.open(filee);
FileOutputStream out = new FileOutputStream(file);
wb.write(out);
out.close();
//code continues...
wb.write(out) opens the file successfully. I have read tons of posts/articles/docs all using that close() method to close out an XSSF Excel file but it does not work here.
How do I solve the problem?
You cannot overwrite the input document this way, as clearly documented in the Javadoc for POIXMLDocument#write(OutputStream o) which is inherited by XSSFWorkBook:
Note - if the Document was opened from a File rather than an InputStream, you must write out to a different file, overwriting via an OutputStream isn't possible

I create Excel file using apache poi. but when i open the excell file it says malformed file need to recover

when i open the file it says malformed file and need to recover. when i press okay it opens and the data i wrote is there. it says**(Excel completed file level validation and repair. Some parts of this workbook may have been repaired or discarded.)** i want to correct this error. how do i make this malformed excel file to well formed excel file?
here is the writing part.
ArrayList<Schedule> schds = serviceResponce.getSchedules();
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("sheet");
CellStyle styleHeaders;
DataFormat format = workbook.createDataFormat();
CellStyle styleDataCells;
DataFormatter downloadForatter=new DataFormatter();
styleDataCells = workbook.createCellStyle();
for (Schedule sch : schds) {
Row row = sheet.createRow(++rowCount);
Cell cellScheduleId = row.createCell(0);
Cell cellRouteId = row.createCell(1);
Cell cellDepTime = row.createCell(2);
Cell cellArrTime = row.createCell(3);
Cell cellFromTo = row.createCell(4);
Cell cellDay = row.createCell(5);
Cell cellStatus = row.createCell(6);
downloadForatter.formatCellValue(cellDay);
cellScheduleId.setCellValue(Integer.parseInt(sch.getSchedule_id()));
styleDataCells.setDataFormat(format.getFormat("0"));
cellScheduleId.setCellStyle(styleDataCells);
cellRouteId.setCellValue(Integer.parseInt(sch.getRoute_id()));
styleDataCells.setDataFormat(format.getFormat("0"));
cellRouteId.setCellStyle(styleDataCells);
cellDepTime.setCellValue(sch.getDeptature_time());
styleDataCells.setDataFormat(format.getFormat("hh:mm"));
cellDepTime.setCellStyle(styleDataCells);
cellArrTime.setCellValue(sch.getArrival_time());
styleDataCells.setDataFormat(format.getFormat("hh:mm"));
cellArrTime.setCellStyle(styleDataCells);
cellFromTo.setCellValue(sch.getFrom_to());
styleDataCells.setDataFormat(format.getFormat("#"));
cellFromTo.setCellStyle(styleDataCells);
cellDay.setCellValue(sch.getDay());
styleDataCells.setDataFormat(format.getFormat("#"));
cellDay.setCellStyle(styleDataCells);
if (sch.getStatus().equals("Y")) {
cellStatus.setCellValue("Active");
styleDataCells.setDataFormat(format.getFormat("#"));
cellStatus.setCellStyle(styleDataCells);
} else {
cellStatus.setCellValue("Inactive");
styleDataCells.setDataFormat(format.getFormat("#"));
cellStatus.setCellStyle(styleDataCells);
}
}
try {
String downloadPath = getServletContext().getRealPath("/") + "ExpSchedules.xlsx";
File excelFile = new File(downloadPath);
if (excelFile != null && excelFile.exists()) {
excelFile.delete();
}
excelFile.createNewFile();
FileOutputStream outputStream = new FileOutputStream(downloadPath);
workbook.write(outputStream);
workbook.close();
log.info("path " + downloadPath);
//
String original_filename = "ExpSchedules.xlsx";
ServletContext sc = this.getServletContext();
InputStream is = new FileInputStream(excelFile);
if (is != null && is.available() > 0) {
log.info("IS is not null");
} else {
log.info("IS is null");
}
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=\"" + original_filename + "\"");
//
// File file = new File(downloadPath);
// FileInputStream fileIn = new FileInputStream(file);
ServletOutputStream outA = response.getOutputStream();
//
byte[] outputByte = new byte[4096];
//
while (is.read(outputByte, 0, 4096) != -1) {
outA.write(outputByte, 0, 4096);
}
is.close();
outA.flush();
outA.close();
Assuming that you're talking about the file that you download from the Servlet and not the file that you create on the server.
Issue is with the following portion of the code.
byte[] outputByte = new byte[4096];
while (is.read(outputByte, 0, 4096) != -1) {
outA.write(outputByte, 0, 4096);
}
You're always trying to write 4096 bytes in the response output stream. Your file content won't always be a multiple of 4096, this code should be modified as below.
byte[] outputByte = new byte[4096];
int readLen = -1;
while ( (readLen = is.read(outputByte)) != -1) {
outA.write(outputByte, 0, readLen);
}
Apart from it there's are multiple issues with this code. Check following
You shouldn't close response output stream, let the Servlet container handle it. Rule is if you didn't open it, don't close it.
You're expecting that only one user will download file at one time, but Servlet container is multithreaded environment. Meaning multiple users can call the download Servlet at the same time. Then this code will be writing to the same file in two different threads, which will either generate exception or will corrupt the file. You need to create the a random name for the output file, or better yet use File.createTempFile(). After it's flushed to the response output stream, delete it.
Finally please modulerize the code, separate the file creation code into another method.

Setting Password Protection on XSSF Workbook

I would like to add password protection to a xlsx file created with poi 3.14.
The documentation claims, that this is possible:
http://poi.apache.org/encryption.html
Using the example I tried it like this:
public static void main(String[] args)
{
try(Workbook wb = new XSSFWorkbook())
{
//<...>
try(ByteArrayOutputStream baos = new ByteArrayOutputStream())
{
wb.write(baos);
byte[] res = baos.toByteArray();
try(ByteArrayInputStream bais = new ByteArrayInputStream(res))
{
try(POIFSFileSystem fileSystem = new POIFSFileSystem(bais);) // Exception happens here
{
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
Encryptor enc = info.getEncryptor();
enc.confirmPassword("pass");
OutputStream encryptedDS = enc.getDataStream(fileSystem);
OPCPackage opc = OPCPackage.open(new File("example.xlsx"), PackageAccess.READ_WRITE);
opc.save(encryptedDS);
opc.close();
}
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
Unfortunately, the code in the example is not compatible to XLSX files and as a result I receive the following exception:
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 (eg XSSF instead of HSSF)
Can anybody help please? I am unable to find the correct alternative for XLSX...
Thank you all for you help. Here is my working result:
public static void main(String[] args)
{
try(Workbook wb = new XSSFWorkbook())
{
Sheet sheet = wb.createSheet();
Row r = sheet.createRow(0);
Cell cell = r.createCell(0);
cell.setCellType(Cell.CELL_TYPE_STRING);
cell.setCellValue("Test");
try(POIFSFileSystem fileSystem = new POIFSFileSystem();)
{
EncryptionInfo info = new EncryptionInfo(EncryptionMode.standard);
Encryptor enc = info.getEncryptor();
enc.confirmPassword("pass");
OutputStream encryptedDS = enc.getDataStream(fileSystem);
wb.write(encryptedDS);
FileOutputStream fos = new FileOutputStream("C:/example.xlsx");
fileSystem.writeFilesystem(fos);
fos.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
You've mis-read the documentation on encrypting in OOXML file. You're therefore incorrectly trying to load your file using the wrong code, when you just need to save it
Without any error handling, your code basically wants to be
// Prepare
POIFSFileSystem fs = new POIFSFileSystem();
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes192, HashAlgorithm.sha384, -1, -1, null);
Encryptor enc = info.getEncryptor();
enc.confirmPassword("foobaa");
// Create the normal workbook
Workbook wb = new XSSFWorkbook();
Sheet s = wb.createSheet();
// TODO Populate
// Encrypt
OutputStream os = enc.getDataStream(fs);
wb.save(os);
opc.close();
// Save
FileOutputStream fos = new FileOutputStream("protected.xlsx");
fs.writeFilesystem(fos);
fos.close();

NotOLE2FileException: Invalid header signature; read 0x0000000000000000, expected 0xE11AB1A1E011CFD0 - file appears not to be a valid OLE2 document

try {
File file = new File("file4.xls");
if (!file.exists()) file.createNewFile();
FileInputStream fis = new FileInputStream(file);
POIFSFileSystem fileSystem = new POIFSFileSystem(fis);
// FileInputStream fis = new FileInputStream(file);
HSSFWorkbook workbook = new HSSFWorkbook(fileSystem);
//Sheet sheet = workbook.createSheet("sheet0");
Sheet sheet = workbook.getSheet("sheet1");
sheet.createRow(0).createCell(0).setCellValue("HelloWorld");
Cell cell = sheet.createRow(1).createCell(0);
cell.setCellValue("Value_1_1");
fis.close();
FileOutputStream fos = new FileOutputStream(file);
workbook.write(fos);
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
I am trying to create simple excel file using java. I am getting above mentioned error.
Open the file once.
Check your file once on click save as. If it is generated from HTML it will show as Web page(*.htm , .html) below drop down to the file.
You can save as Excel 97-2003 Workbook (.xls) and retry to read from code. It worked in my case.
Your problem is this line here:
if (!file.exists()) file.createNewFile();
That creates a brand new 0 byte file, which is not a valid Excel file. That's why POI objects.
Also, you're using an old version of Apache POI. Newer ones give a more helpful exception if you're silly enough to ask them to read a zero byte file
Taking account of the advice on Files vs InputStreams, but noting you're doing an in-place write which isn't yet fully supported on an opened File, change your code to be more like:
Workbook workbook = null;
File file = new File("file4.xls");
if (!file.exists()) {
if (file.toString().endsWith(".xlsx")) {
workbook = new XSSFWorkbook();
} else {
workbook = new HSSFWorkbook();
}
} else {
workbook = WorkbookFactory.create(new FileInputStream(file));
}
That will work for both .xls and .xlsx files, and avoids your errro
Though you really ought to upgrade your version of Apache POI too...

File Excel From Apache POI Cant Open by Ms Excel (corrupt)

I don't know why the file I write using POI cant be opened by Ms Excel 2013, but the file is still readable by POI. (cell value can be changed)
this is the error from file
here is the code
FileInputStream fis = null;
try {
fis = new FileInputStream(fileUri); //not error at fileUri
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String urii = fileUri.replace(".xls", "0.xls"); //not error
File fisx = new File(urii);
Workbook workbook = null;
workbook = new HSSFWorkbook(fis);
Sheet sheet = workbook.getSheetAt(0);
Row row = sheet.getRow(0);
Cell cell = row.getCell(0);
String p = cell.getStringCellValue();
TextView a = (TextView) findViewById(R.id.txtUri);
cell.setCellValue(new String("popo"));
String x = cell.getStringCellValue();
TextView b = (TextView) findViewById(R.id.txtFile);
a.setText(p);
b.setText(x);
OutputStream fos = null;
fos = new FileOutputStream(fisx);
workbook.write(fos); //main problem
fos.flush();
fos.close();
Thanks for your help!!
There are two issues with your code. Firstly this:
FileInputStream fis = null;
try {
fis = new FileInputStream(fileUri);
As explained in the Apache POI Docs, don't use an InputStream if you have a File!
Secondly, this:
Workbook workbook = null;
workbook = new HSSFWorkbook(fis);
That will only work for .xls files, not for .xlsx ones. Instead, you need to use WorkbookFactory which identifies the type and gives you the right workbook for the format
So, change your code to be
File file = new File(fileUri);
Workbook workbook = WorkbookFactory.create(file);
The major problem that i see here is:
Workbook workbook = null;
workbook = new HSSFWorkbook(fis);
Instead you have to use:
Workbook workbook = null;
workbook = new XSSFWorkbook(fis);
TO be readable by MS EXCEL 2013.
Solved :
by using real android device instead of bluestack emulator,
I dont know why, but it works!!
Thanks everyone :D
You are calling getSheetAt(0) but you did not create any sheet before (workbook.createSheet(“name”)
The solution is to use the .xls extension and NOT .xlsx, as outlined in this answer

Categories