casting object from XSSFWorkbook and SXSSFWorkbook - java

I use a template file containing 2 tables on first sheet. I need to perform 2 operations on first sheet.
There is Locations data table column headers(ex. sr.no, Location and related data fields) in which I need to use XSSFWorkbook so that I may shift rows down according to size of locations.
There is Devices Table, in which I need to use streaming api i.e. SXSSFWorkbook object
I created workbook object using XSSFWorkbook, shifted rows down and then tried to cast workbook into SXSSFWorkbook. But it throws error while in execution
java.lang.IllegalArgumentException: Attempting to write a row[11] in the range [0,30] that is already written to disk.
If I first create workbook obj using SXSSFWorkbook, it is not possible to create
XSSFWorkbook from it. Can someone please suggest how it can be done.
I tried :
FileInputStream inputStream = new FileInputStream(new File(filePath));
XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
XSSFSheet sheet = workbook.getSheet("Sheet1");
// First shift rows down - WORKS FINE
sheet.shiftRows( tab1HeaderRowNum + 1, sheet.getLastRowNum(), locationRecordsSize - 1);
// Copy style of row on new rows - WORKS FINE
for(int i = 1; i < locationRecordsSize; i++){
sheet.copyRows(tab1HeaderRowNum , tab1HeaderRowNum , (tab1HeaderRowNum + i), cellCopyPolicy);
}
// Create new SXSSFWorkbook
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(workbook);
SXSSFSheet sxssfSheet = sxssfWorkbook.getSheet("Sheet1");
if(sxssfSheet.getRow(rowNum) == null){ // rowNum is of row which is newly added using shiftRows
row = sxssfSheet.createRow(rowNum); // Error Occurs Here
}else{
row = sxssfSheet.getRow(rowNum);
}
Im using Apache POI 3.15

Related

How to add columns to an existing large excel file using SXSSF Apache POI?

I am working with a large excel file ( larger than 40 Mb , more than 100k rows and 50 columns ). I am successfully reading it using POI ( 3.10.1 version ) event stream and then doing some calculation and storing result into a List.
Now I have to append this List as a column in the same file. In this part I am facing issue.
I have tried to achieve this by using the below code
FileInputStream excelFile = new FileInputStream(new File(pathToFile));
Workbook workbook = new XSSFWorkbook(excelFile);
Sheet datatypeSheet = workbook.getSheetAt(0); // Get first sheet
Iterator<Row> iterator = datatypeSheet.iterator();
int i=0;
while (iterator.hasNext()) { // Loop over each row
Row currentRow = iterator.next();
Cell cell = currentRow.createCell(currentRow.getLastCellNum());
cell.setCellType(Cell.CELL_TYPE_STRING);
if(currentRow.getRowNum() == 0)
cell.setCellValue("OUTPUT-COLUMN"); // set column header for the new column
else {
cell.setCellValue(list.get(i)); // list contains the output to populate in new column
i++;
}
}
FileOutputStream fos = new FileOutputStream(new File(pathToOutput));
workbook.write(fos);
fos.close();
It is working fine with smaller files But the issue is that I am getting Out of memory for the larger files. Now I tried to modify this and use SXSSF in place of XSFF to get over the memory issue (See below code). But while testing even for smaller files I am getting output file same as the input file.
FileInputStream excelFile = new FileInputStream(new File(pathToFile));
XSSFWorkbook xwb = new XSSFWorkbook(inputStream);
inputStream.close();
SXSSFWorkbook wb = new SXSSFWorkbook(xwb,100);
wb.setCompressTempFiles(true);
SXSSFSheet sh = (SXSSFSheet) wb.getSheetAt(0);
Iterator<Row> iterator = datatypeSheet.iterator();
int i=0;
while (iterator.hasNext()) { // Loop over each row
Row currentRow = iterator.next();
Cell cell = currentRow.createCell(currentRow.getLastCellNum());
cell.setCellType(Cell.CELL_TYPE_STRING);
if(currentRow.getRowNum() == 0)
cell.setCellValue("OUTPUT-COLUMN"); // set column header for the new column
else {
cell.setCellValue(list.get(i)); // list contains the output to populate in new column
i++;
}
}
FileOutputStream fos = new FileOutputStream(new File(pathToOutput));
wb.write(fos);
fos.close();
Using a db is not suitable in my use case and i want to avoid using a temporary data structure to hold data for writing due to memory constraint.
Is there a way to write in output workbook while streaming ? Here is the code that I am using to read using POI Streaming API
private class ExcelData implements SheetContentsHandler {
LinkedHashMap<Strin, String> rowMap;
public void startRow(int rowNum) {
}
public void endRow(int rowNum) {
// Process the row
// Handle write to output workbook ??
}
public void cell(String cellReference, String formattedValue,
XSSFComment comment) {
// Save current row in rowMap ( column name => cell value )
}
public void headerFooter(String text, boolean isHeader, String tagName)
{
}
}
It is not possible to add column to existing workbook using POI SXSSF. It only allows addition of new rows.
The only solution is to read the existing workbook and write to a new workbook with the added column.
To achieve this we can store the rows in a data structure or database in the endrow() method and then use the persisted data to write a new workbook.

XSSF(Apache POI) - Adding multiple column label from single column value in pivot table

I am currently using the Apache POI 3.12 for adding pivot table. Here my sample.xlsx file :
Now I using the following code for creating the pivot table for the above data.
File excel = new File("sample.xlsx");
FileInputStream fis = new FileInputStream(excel);
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sheet = wb.getSheetAt(0);
XSSFPivotTable pivotTable = sheet.createPivotTable(new AreaReference("A3:C7"), new CellReference("E3"));
pivotTable.addRowLabel(0);
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
pivotTable.addDataColumn(1, true);
pivotTable.addReportFilter(2);
FileOutputStream fileOut = new FileOutputStream("output.xlsx");
wb.write(fileOut);
fileOut.close();
wb.close();
My output.xlsx file have the following pivot table :
When I am going to edit the pivot table in excel it adding the year column in page fields not column fields. Actually I need the following result :
I can't add multiple column label from single column value. Could you please help me? Thanks in advance
The class XSSFPivotTable is in #Beta state. So this is only possible using the underlaying low level objects.
XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream("sample.xlsx"));
XSSFSheet sheet = wb.getSheetAt(0);
//the following creates a Pivot Table with 3 PivotFields (0 to 2) (3 Columns A3:C7); all dataField="false" at first
XSSFPivotTable pivotTable = sheet.createPivotTable(new AreaReference(new CellReference("A3"), new CellReference("C7")), new CellReference("E3"));
//the following makes PivotFields(0) an Axis-Field AXIS_ROW with 5 Items (5 Rows A3:C7). Why one Item for each row? I don't know.
//and it adds a new RowField for this
pivotTable.addRowLabel(0);
//the following makes PivotFields(1) a DataField and creates a DataColumn for this
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
//pivotTable.addDataColumn(2, false); //not neccessary since addColumnLabel already adds a DataColumn
//now PivotFields(2) needs to be an Axis-Field AXIS_COL
pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(2).setAxis(
org.openxmlformats.schemas.spreadsheetml.x2006.main.STAxis.AXIS_COL);
//PivotFields(2) needs to have at least one Item
pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(2).addNewItems();
pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(2).getItems().addNewItem().setT(
org.openxmlformats.schemas.spreadsheetml.x2006.main.STItemType.DEFAULT);
//new ColField needs to be added
pivotTable.getCTPivotTableDefinition().addNewColFields().addNewField().setX(2);
//pivotTable.addReportFilter(2);
FileOutputStream fileOut = new FileOutputStream("output.xlsx");
wb.write(fileOut);
fileOut.close();
wb.close();
The pivotTable.addDataColumn(1, true); is not neccessary since addColumnLabel already adds a DataColumn.

Cant write more than one row in excell sheet using POI

I'm developing an app in java using POI, which writes data into excell sheet.
I want to write a new row when I have a new data (in order to assist the user to follow the data).
I dont want to close and reopen the excell file each time I have a new data to write.
The initilize code is:
FileOutputStream fileOut = new FileOutputStream(new File (excellFileName));
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("FirstSheet");
rowNum = 0;
HSSFRow rowhead = sheet.createRow((short)rowNum);
createRowColumns(rowhead, rowNum);
workbook.write(fileOut);
rowNum++;
Each time I have a new data, I'm using this code:
HSSFRow rowMsg = sheet.createRow((short)rowNum);
createRowColumns(rowMsg, rowNum);
workbook.write(fileOut);
rowNum++;
(createRowColumns mehtod sets the data (in seperate cells in a new: rowMsg)
The problem is that I cant see any rows in the excell file, except the first row (rowhead , row #0).
What Am I missing ?
(Pay attention that I dont want to close and reopen the file each time I have data to write)
Thanks
To write all rows you have to write to worksheet only once. So, you need to update your code as follows.
for(int index = 0; index < rowNum; rowNum++) {
HSSFRow rowMsg = sheet.createRow((short)rowNum);
createRowColumns(rowMsg, rowNum);
}
workbook.write(fileOut);

adding cells in excel with java apache

I am reading an already existing excel file and trying to add certain cells for example(C4-C15). I am having difficult manipulating the files through java. I am using apache poi, and would appreciate any help or direction.
In order to access a cell in Apache POI, you have to get a row first, and then get cell within chosen row. Below is example:
//Input file
InputStream inp = new FileInputStream("workbook.xls");
//Create workbook instance
Workbook wb = WorkbookFactory.create(inp);
//Create sheet instance
Sheet sheet = wb.getSheetAt(0);
for(int i = 3; i <= 16; ++i){ //Rows from 4 to 15 (Apache POI is zero based)
Row row = sheet.getRow(i);
Cell cell = row.getCell(2); //Column "C"
//Do something with cell
}
// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();
Source (more examples here)

Open EXISTING xls in Apache POI

I have an existing file (C:\wb.xls) that I want to open and make changes to. How in Apachie POI do you open an existing file? All the documentation that I find has to go with creating a new file. And if you know, how do you insert a new row at the top of the xls file or how to autoformat column widths?
Use one among the following
XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(xlFileAddress));
OR
Workbook wb = WorkbookFactory.create(new File(xlFileAddress));
OR
Workbook wb = WorkbookFactory.create(new FileInputStream(xlFileAddress));
and then use wb for creating/reading/updating sheets/rows/cell whatever you want. For detail visit here. This will definitely help you.
Did you try reading the Apache POI HowTo "Reading or modifying an existing file"? That should cover you...
Basically, what you'll want to do is taken from the QuickGuide eg this for loading a File
Workbook wb = WorkbookFactory.create(new File("MyExcel.xls"));
Sheet s = wb.getSheetAt(0);
// Get the 11th row, creating if not there
Row r1 = s.getRow(10);
if (r1 == null) r1 = s.createRow(10);
// Get the 3rd column, creating if not there
Cell c2 = r1.getCell(2, Row.CREATE_NULL_AS_BLANK);
// Set a string to be the value
c2.setCellValue("Hello, I'm the cell C10!");
// Save
FileOutputStream out = new FileOutputStream("New.xls");
wb.write(out);
out.close();

Categories

Resources