Apache poi XLSX to XLS - java

I'm working with apache poi, i read some xlsx file, process it and then export them in xlsx format as well. But now i have the requirement of the export format to be XLS (this is to support old devices). Is there an easy way of convert the code-generated xlsx file to xls?
The all process is made with XSSF implementation.
Thanks in advance.

I agree with centic answer, but I want to add a few lines of code.
You said that you are using XSSF implementation.
So, for the workbook that you are saving do the following changes:
change XSSFWorkbook x = new XSSFWorkbook();
to Workbook x = new HSSFWorkbook();
where Workbook is import from org.apache.poi.ss.usermodel.Workbook;
Similarly
Change XSSFRow instantiation from
XSSFRow r = newXSSF();
to Row r = new HSSFRow();
and import the Row from org.apache.poi.ss.usermodel.Row;
Like the same way, change Cell instantiation to ss.usermodel package.
And finally save your HSSF workbook with .xls extension.

You will need to switch to the "ss" implementation which allows to transparently work with both HSSF (=XLS) and XSSF (=XSLX), see http://poi.apache.org/spreadsheet/converting.html for some details of the original HSSF -> SS switch which should also shed some light on supporting it for the other way around.
Then only the two constructors for HSSFWorkbook/XSSFWorkbook are needed to decide which of the two formats you want to produce.

I have faced same scenario and implemented below code for Coverting XLSX to XLS using Java
Below code will read it from directory and process using apache camel (polling file from path) and apace poi
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Optional;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class ExcelFileProcessor implements Processor {
final Logger logger = LoggerFactory.getLogger(getClass());
#Value("${test.dir.in}")
private String inDir;
#Override
public void process(Exchange exchange) throws Exception {
logger.info("Entry-ExcelFileProcessor- Process method");
long start = System.currentTimeMillis();
String fileNameWithExtn=(String) exchange.getIn().getHeader("camelFileName");
Long originalFileSize = (Long) exchange.getIn().getHeader("CamelFileLength");
String fileNameWithOutExtn = fileNameWithOutExtn(fileNameWithExtn);
logger.info("fileNameWithExtn:{}" ,fileNameWithExtn);
logger.info("fileNameWithOutExtn:{}" ,fileNameWithOutExtn);
logger.info("originalFileSize:{}" ,originalFileSize);
try(InputStream in = exchange.getIn().getBody(InputStream.class);
XSSFWorkbook wbIn = new XSSFWorkbook(in);
Workbook wbOut = new HSSFWorkbook();) {
int sheetCnt = wbIn.getNumberOfSheets();
for (int i = 0; i < sheetCnt; i++) {
Sheet sIn = wbIn.getSheetAt(0);
Sheet sOut = wbOut.createSheet(sIn.getSheetName());
Iterator<Row> rowIt = sIn.rowIterator();
while (rowIt.hasNext()) {
Row rowIn = rowIt.next();
Row rowOut = sOut.createRow(rowIn.getRowNum());
Iterator<Cell> cellIt = rowIn.cellIterator();
while (cellIt.hasNext()) {
Cell cellIn = cellIt.next();
Cell cellOut = rowOut.createCell(cellIn.getColumnIndex(), cellIn.getCellType());
switch (cellIn.getCellType()) {
case Cell.CELL_TYPE_BLANK: break;
case Cell.CELL_TYPE_BOOLEAN:
cellOut.setCellValue(cellIn.getBooleanCellValue());
break;
case Cell.CELL_TYPE_ERROR:
cellOut.setCellValue(cellIn.getErrorCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
cellOut.setCellFormula(cellIn.getCellFormula());
break;
case Cell.CELL_TYPE_NUMERIC:
cellOut.setCellValue(cellIn.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
cellOut.setCellValue(cellIn.getStringCellValue());
break;
}
CellStyle styleIn = cellIn.getCellStyle();
CellStyle styleOut = cellOut.getCellStyle();
styleOut.setDataFormat(styleIn.getDataFormat());
cellOut.setCellComment(cellIn.getCellComment());
}
}
}
File outF = new File(inDir+fileNameWithOutExtn+".xls");
try(OutputStream out = new BufferedOutputStream(new FileOutputStream(outF));){
wbOut.write(out);
}
}catch (Exception e) {
logger.info("Error during Excel file process:{}",e.getMessage());
}
long end = System.currentTimeMillis();
logger.info("Total time processed for file in - {} ms", (end - start));
logger.info("Exit-FileProcessor- Process method");
}
public String fileNameWithOutExtn(String fileName) {
return Optional.of(fileName.lastIndexOf('.')).filter(i-> i >= 0)
.map(i-> fileName.substring(0, i)).orElse(fileName);
}
}
If you are not using camel and want to get inputstream from file use below snippet
String inpFn = "input.xlsx";
String outFn = "output.xls";
InputStream in = new BufferedInputStream(new FileInputStream(inpFn));
try {
Workbook wbIn = new XSSFWorkbook(in);
File outF = new File(outFn);
if (outF.exists())
outF.delete();
Workbook wbOut = new HSSFWorkbook();
//continue with above code

Related

Apache POI conversion issue from XSSFWorkbook to SXSSFWorkbook, Macros are disabled for the downloaded file

Requirement : To read upload and download large files which are macro based .xlsm files. To work with .xlsm they only way is to read and re-write from an existing template .xlsm file as per my best knowledge from apache poi documentation and certain post on stackoverflow, please correct me if I'm wrong anywhere.
A XSSFWorkbook is created from an existing "sample_macro.xlsm" file, and further casted into SXSSFWorkbook to address some memory issues for huge data.
Workbook workbook = new SXSSFWorkbook((XSSFWorkbook) getWorkbookFromTemplateFile());
The file is populated with data and gets downloaded on user's machine works, below is the working code.
Issue : When this file is downloaded and used further for some upload purposes, the rows are not readable and the file is considered to have no rows, until its not opened and saved again in Microsoft Excel.
Once the file is open, saved and uploaded this time it works fine and data renders on the screen.
If someone can help to understand what is going wrong, or is this a bug with SXSSFWorkbook and need to be addressed ?
Below is the reproducible code for reference.
Kindly use any sample .xlsm file to reproduce it, cant share the macro based file due to sensitive information.
Controller:
package com.experiment.controller;
import com.experiment.service.IFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class FileController {
#Autowired
private IFileService fileService;
#GetMapping(path = "/download",
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE,
consumes = MediaType.ALL_VALUE)
public ResponseEntity<byte[]> getFile() {
String filename = "test.xlsm";
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename)
.contentType(MediaType.parseMediaType("application/vnd.ms-excel.sheet.macroEnabled.12"))
.body(fileService.download());
}
}
Service:
package com.experiment.service.impl;
import com.experiment.service.IFileService;
import lombok.SneakyThrows;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Objects;
#Service
public class FileServiceImpl implements IFileService {
private Workbook templateWorkbook;
private static final String TEMPLATE_PATH = "templates/sample_macro.xlsm";
#SneakyThrows
#Override
public byte[] download() {
Workbook workbook = new SXSSFWorkbook((XSSFWorkbook) getWorkbookFromTemplateFile()); // casting to SXSSFWorkbook
populateMultiSheetWorkbook(workbook); // This writes data to multiple sheets in the workbook
ByteArrayOutputStream out = new ByteArrayOutputStream();
workbook.write(out);
return out.toByteArray();
}
private void populateMultiSheetWorkbook(final Workbook workbook) {
Sheet sheet1 = workbook.getSheet("Sheet1"); // Enter the sheet name
final Row row = sheet1.createRow(1);
final Cell cell1 = row.createCell(0);
cell1.setCellValue("Test Data Sheet 1");
Sheet sheet2 = workbook.getSheet("Sheet2"); // Enter the sheet name
final Row row2 = sheet2.createRow(1);
final Cell cell2 = row.createCell(0);
cell2.setCellValue("Test Data Sheet 2");
}
#SneakyThrows
private Workbook getWorkbookFromTemplateFile() {
// macro template file located in src/main/resources/templates/sample_macro.xlsm
byte[] template = Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream(TEMPLATE_PATH)).readAllBytes();
if (template == null) {
throw new Exception("Error reading file");
}
templateWorkbook = new XSSFWorkbook(new ByteArrayInputStream(template));
return templateWorkbook;
}
}
Temporary Solution but not a proper solution:
Process the workbook and save into a new file on some server path e.g. test123.xlsm
Run the vbs script as per the link and apply for test123.xlsm ->
To Open, Save & Close the .xlsm file
3. Read the test123.xlsm file & return the byte[] as response back to user.

Formatting Excel Spreadsheet using Apache POI in JAVA

My intention is to set the border for the contents of the spreadsheet data while maintaining the other properties of the cell as it is.
The below code formats(setting border) the whole spreadsheet rather than formatting only the portion of spreadsheet where there is actual data.
Is there a reason why the formatting is applied throughout the spreadsheet? And is there a way to overcome this?
package learning.selenium.self.begining;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Iterator;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
public class testing {
public static void main(String[] args) throws Exception {
File myFile = new File("TestFile.xlsx");
Workbook myWorkbook = WorkbookFactory.create(new FileInputStream(myFile));
Sheet mySheet = myWorkbook.getSheetAt(0);
Iterator<Row> r = mySheet.rowIterator();
while (r.hasNext()) {
Row myR = r.next();
Iterator<Cell> c = myR.cellIterator();
while (c.hasNext()) {
Cell myC = c.next();
System.out.println("precessing (" + myR.getRowNum() + "," + myC.getColumnIndex() + ")");
CellStyle s = myC.getCellStyle();
s = myC.getCellStyle();
s.setBorderBottom(BorderStyle.THIN);
s.setBorderTop(BorderStyle.THIN);
s.setBorderLeft(BorderStyle.THIN);
s.setBorderRight(BorderStyle.THIN);
myC.setCellStyle(s);
}
}
FileOutputStream fos = new FileOutputStream(myFile);
myWorkbook.write(fos);
fos.close();
}
}
I dont know if this helps but is worth checking out
CellRangeAddress range= new CellRangeAddress(firstrow, lastrow, firstcol, lastcol);
RegionUtil.setBorderBottom(BorderStyle.THIN, range, sheet);
Same way u can set for other borders.

Poi api XSSFWorkbook sheet cast EXCEPTION

package apsel5;
import java.io.FileInputStream;
import java.util.Iterator;
import org.apache.poi.sl.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class A {
public static void main(String[] args) throws Exception{
FileInputStream f = new FileInputStream("D:\\LeadSuite.xlsx");
XSSFWorkbook wbks = new XSSFWorkbook(f);
Sheet s = (Sheet) wbks.getSheet("TestSteps");
Iterator itr = s.iterator();
while(itr.hasNext()){
Row rowitr = (Row)itr.next();
Iterator cellitr = rowitr.cellIterator();
while(cellitr.hasNext()){
Cell cell1= (Cell)cellitr.next();
switch(cell1.getCellType()){
case Cell.CELL_TYPE_STRING:
System.out.println(cell1.getStringCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
System.out.println(cell1.getNumericCellValue());
break;
case Cell.CELL_TYPE_BOOLEAN:
System.out.println(cell1.getBooleanCellValue());
break;
}
}
}
}
}
I get an exception after running the above code:
Exception in thread "main" java.lang.ClassCastException:
org.apache.poi.xssf.usermodel.XSSFSheet cannot be cast to
org.apache.poi.sl.usermodel.Sheet
You imported the wrong version of Sheet. Simply turn
import org.apache.poi.sl.usermodel.Sheet;
into
import org.apache.poi.ss.usermodel.Sheet;
that represents the Excel worksheet, and your code should work. No cast should be needed for Sheet, Row and Cell.
If you look at the XSSFSheet class definition, you can see that it implements org.apache.poi.ss.usermodel.Sheet. On the other hand, the org.apache.poi.sl.usermodel.Sheet interface is related with PowerPoint; in fact, according to the Javadoc, it's the
Common parent interface for Slides, Notes and Masters
So .ss. = Excel (XSSF), and .sl. = PowerPoint (XSLF). The fact that these two interfaces have the same name may actually be misleading.

How to write data of a column to output excel from input excel using JAVA POI

My Requirement is to read data from input excel file and write it in output excel file I am using JAVA 8 AND APACHE POI
During the write process I am changing the date format for a particular column from mm/dd/yyyy to dd/mm/yyyy
With below code its setting current date in excel, I want to set same values of input excel in output excel but with new format defined.
Any help would be really appreciated
Below is Updated code:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFCreationHelper;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
class DateFormatDemo1{
public static void main( String[] args ) throws IOException, InvalidFormatException, ParseException
{
OPCPackage pkg = OPCPackage.open(new File("C:\\DateFormatIssue\\SourceFile\\S.xlsx"));
XSSFWorkbook wb = new XSSFWorkbook(pkg);
XSSFCreationHelper createHelper = wb.getCreationHelper();
XSSFSheet sheet = wb.getSheetAt(0); // Create spreadsheet in workbook
Iterator<Row> iterator = sheet.iterator();
Cell cell = null;
Row row=null;
row=iterator.next();
int pos=11;
while(iterator.hasNext())
{
row=iterator.next();
cell= row.getCell(pos-1);
XSSFCellStyle cellStyle = (XSSFCellStyle)cell.getCellStyle();
cellStyle.setDataFormat( createHelper.createDataFormat().getFormat("M/dd/yyyy")); // set the format of the date
SimpleDateFormat sdf = new SimpleDateFormat("d/M/yyyy");
Date d=null;
/** below if block converts dates which are in format d/M/yyyy (15/04/2017) to M/d/yyyy (4/15/2017)**/
if (cell.getCellType() == Cell.CELL_TYPE_STRING)
{
d= sdf.parse(cell.getStringCellValue());
cell.setCellValue(d);
cell.setCellStyle(cellStyle);
}
else if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC)
{
cell.setCellValue(cell.getNumericCellValue());
}
}
FileOutputStream outFile =new FileOutputStream(new File("C:\\DateFormatIssue\\OutputFile\\output.xlsx"));
wb.write(outFile);
wb.close();
outFile.close();
pkg.close();
}}

Error: Could not find or load main class excel2JSON.excel

package excel2JSON;
import java.io.File;
import java.io.FileInputStream;
import java.util.Iterator;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.json.JSONArray;
import org.json.JSONObject;
public class excel {
public static void main(String[] args)
{
String str = ExcelToJSON(new File ("C:\\workbook.xlsx"));
System.out.println("JSON = " + str);
}
private static String ExcelToJSON(File file_open)
{
JSONObject json = null;
try {
FileInputStream input = new FileInputStream(file_open);
Workbook workbook = WorkbookFactory.create(input);
Sheet sheet = workbook.getSheetAt(0);
json = new JSONObject();
JSONArray rows = new JSONArray();
for (Iterator<Row> rows_it = sheet.rowIterator(); rows_it.hasNext();) {
Row row = rows_it.next();
JSONObject jason_row = new JSONObject();
JSONArray cells = new JSONArray();
for (Iterator<Cell> cells_it = row.cellIterator(); cells_it.hasNext();) {
Cell cell = cells_it.next();
//Check the cell type and format accordingly
switch (cell.getCellType())
{
case Cell.CELL_TYPE_NUMERIC:
double numeric=cell.getNumericCellValue();
cells.put(String.valueOf(numeric));
break;
case Cell.CELL_TYPE_STRING:
cells.put(cell.getStringCellValue());
break;
}
}
jason_row.put("cell", cells);
rows.put(jason_row);
}
// Create the JSON.
json.put("rows", rows);
} catch (Exception e) {
e.printStackTrace();
}
// Get the JSON text.
return json.toString();
}
}
getting this error:
Error: Could not find or load main class excel2JSON.excel
I don't know why i am getting this error. I am new to Java and i need help to fix this issue. I am trying to convert Excel file to JSON document. This is the code i wrote for that but i am getting issue when i run the program in Eclipse.
The most common cause of this error in eclipse is when you have moved the class around, Eclipse will be trying to use an outdated run configuration which will not work.
Click the down arrow next to the green play button in Eclipse, select Run Configurations.
Delete the references to this class, then close that window, select the excel class. Click the down arrow next to the play button again and select run as Java Application.

Categories