Trim sheet name in Sheet interface (Apache POI) - java

I'm trying to get Sheet by using:
Sheet sheet=workbook.getSheet("sheetName");
But in my workbook, some sheet names has whitespaces. How to make "trim search"? Is is possible to do something like this:
Sheet sheet=workbook.trimSheetSearch("sheetName");
Or
Sheet sheet=workbook.indexOfSheetSearch("sheetName");

You should be able to iterate each Sheet to improve your search with Workbook.getNumberOfSheets() and Workbook.getSheetAt(int index).
Something like :
for(int i = 0; i < workbook.getNumberOfSheets(); i++){
String s = workbook.getSheetName(i);
if(checkName(s, nameToFind)) return workbook.getSheetAt(i);
}
return null; // sheet not found
For the search method, you can do a dirty solution like
public boolean checkName(String n1, String n2){
return n1.replaceAll(" ", "").equalsIgnoreCase(n2.replaceAll(" ", ""));
}
I let you improve that method (I will not do everything here ;) ). Note that this might not compile because I don't have an actual system to run this but this should work just fine.

Related

Workbook takes long time to generate excel file

I'm trying to generate excel file with 200k records. But it is taking almost 2 hours to generate the file.
Here is my code of generating excel file.
Workbook workbook=null;
csvFileName = userId+"_Records_"+new SimpleDateFormat("yyyyMMddHHmmss")
.format(new Date())+".xls";
path = ReadPropertyFile.getProperties("download.reports.path");
misService.insertXLSRecord(ackNo,"-",null, VspCommonConstants.getIpFromRequest(request),
new Date(), userId,"N",userReportRoleId);
workbook = getWorkbook(path+csvFileName);
Sheet sheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(studAppForm.get(0)
.getScheme_Id()+"_"+studAppForm.get(0).getEFP_Scholarship_Name(),'_'));
if(schemeQuestionData.containsKey(currSheetSchemeId))
createXLSHeaders(sheet,schemeQuestionData.get(currSheetSchemeId));
Row row = sheet.createRow(++rowCount);
currAppId=studAppForm.get(j).getApp_Id().toString();
jspTableAppIds.remove(jspTableAppIds.indexOf(new BigInteger(currAppId)));
writeBook(studAppForm.get(j), row);
Here is my createXLSHeaders method to create header
void createXLSHeaders( Sheet sheet, List<SchemeMasterBean> schemeMasterBeanList){
LOGGER.info("Creating XLS SheetHeaders for sheet "+sheet.getSheetName());
// Sheet sheet = workbook.createSheet();
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("APPLICATION ID");
header.createCell(1).setCellValue("APPLICATION STATUS");
header.createCell(2).setCellValue("APPLICATION DATE");
header.createCell(3).setCellValue("SCHEME/SCHOLARSHIP APPLIED");
header.createCell(4).setCellValue("SCHEME ID");
header.createCell(5).setCellValue("STUDENT ID");
header.createCell(6).setCellValue("STUDENT FULL NAME");
.
.
.
62 heading...
int i=73;
if(schemeMasterBeanList!=null)
for(SchemeMasterBean schemeMasterBean :schemeMasterBeanList){
if(!schemeMasterBean.getSmSchemeType().equals("5") &&
!schemeMasterBean.getSmSchemeType().equals("6")){
header.createCell(i).setCellValue(schemeMasterBean.getSmScholarshipName());
i++;
}
}
}
and finally writebook method
private void writeBook(StudentAppFormVsp saf, Row row) throws JSONException {
Cell cell = row.createCell(0);
cell.setCellValue(saf.getApp_Id()!=null?saf.getApp_Id().toString():"");
cell = row.createCell(1);
cell.setCellValue(saf.getApp_Status()!=null?getApplicationStatusMap().get(saf.getApp_Status()):"");
cell = row.createCell(2);
cell.setCellValue(saf.getCrtn_time()!=null?saf.getCrtn_time().toString():"");
cell = row.createCell(3);
cell.setCellValue(saf.getEFP_Scholarship_Name()!=null?saf.getEFP_Scholarship_Name().toString():"");
cell = row.createCell(4);
cell.setCellValue(saf.getScheme_Id()!=null?saf.getScheme_Id().toString():"");
cell = row.createCell(5);
cell.setCellValue(saf.getStud_Id()!=null?saf.getStud_Id().toString():"");
.
.
62 rows
}
How to reduce the excel sheet generation time?
First: play around with memory for the application if possible.
Then: the tip on using a profiler is really worth the effort.
Any DOM, XML, Excel or otherwise often suffer from location references searching from top to the actual position.
Creating a DOM instead of writing sequentially is costly with respect to memory, and can slow things down. Maybe consider this.
You could make two loop: writing to a CSV file, and then creating an XLS(X).
Then you know where the complexity resides.
The following (I rewrote a bit) is slightly suspect: toString + new BigInteger points to a conversion; I hope not from BigInteger to String to BigInteger.
StudentAppFormVsp saf = studAppForm.get(j);
currAppId = saf.getApp_Id().toString();
jspTableAppIds.remove(jspTableAppIds.indexOf(BigInteger.valueOf(currAppId)));
writeBook(saf, row);

Can't add worksheets to an excel file through my R script

I'm trying to create a workbook with several spreadsheets where I have to pass three data frames to each sheet. However, I'm having problems creating the sheets, having the following error:
Error in .jcall(wb, "Lorg/apache/poi/ss/usermodel/Sheet;",
"createSheet", : method createSheet with signature
(D)Lorg/apache/poi/ss/usermodel/Sheet; not found
I'm using the xlsx package and the relevant code part is the following:
wb <- createWorkbook(type="xlsx")
saveWorkbook(wb, 'output.xlsx')
for (i in year)
{
sheet.1 <- createSheet(wb, sheetName = i)
data.filter <- realdata[realdata$year_ == i,]
data.filter <- data.filter[data.filter$month_ >= month[1],]
data.filter <- data.filter[data.filter$month_ <= month[4],]
ptable_data_usado <- cast(data.filter, mondat ~ BASE, value = "myidx")
correl_usado <- cor(ptable_data_usado)
addDataFrame(correl_usado, sheet = i, startRow = 0, startColumn = 0)
ptable_data_prx <- cast(data.filter, mondat ~ NearestBaseName, value = "myidx")
correl_prx <- cor(ptable_data_prx)
addDataFrame(correl_prx, sheet = i, startRow = 14, startColumn = 0)
}
I ran into a similar problem. My solution was to coerce sheet name into a character.
So in your case it might be
sheet.1 <- createSheet(wb, sheetName = as.character(i))
Hope it will help.
xlsx package is using rJava to call functions written in JAVA from the APACHE POI project for functionality.
The function to creat worksheet is declared as:
public XSSFSheet createSheet(java.lang.String sheetname)
this means that you need to pass a string to the function. Return back to R, the sheet name must be a character vector. #Oleksii-Sh answer is right.
Or you can use:
sheet.1 <- createSheet(wb, sheetName = paste0("sheet", i))
if you want to name it sheet1, sheet2 ...
Can't be positive without a reproducible example, but it looks like the problem is the two lines where you have sheet = i. Instead, it should be sheet = sheet.1.
In addition, startRow and startColumn need to be integers greater than zero, though that would give an out-of-allowable-range error, rather than a not-found error.
Also, saveWorkbook(wb, 'output.xlsx') should come after the loop.

Apache POI : Update cells in a named range

I am using Apache POI library to read/write to xlsx. In my original xlsx, I have a namedrange "XYZ".
I want to update the values of cells within this name range. How can I do that?
I did this:
XSSFName name = workbook.getName("XYZ");
String formula = name.getRefersToFormula();
System.out.println("Formula = " + formula);
Now, I dont know how to get a handle to individual cell in this named range.
Can anyone please point me to the correct API that I can use?
Rgds
Sapan
There is an example from the Busy Developers' Guide for retrieving the cells in the range. Then you can use Cell.setCellValue() to update.
// setup code
String cname = "TestName";
Workbook wb = getMyWorkbook(); // retrieve workbook
// retrieve the named range
int namedCellIdx = wb.getNameIndex(cname);
Name aNamedCell = wb.getNameAt(namedCellIdx);
// retrieve the cell at the named range and test its contents
AreaReference aref = new AreaReference(aNamedCell.getRefersToFormula());
CellReference[] crefs = aref.getAllReferencedCells();
for (int i=0; i<crefs.length; i++) {
Sheet s = wb.getSheet(crefs[i].getSheetName());
Row r = s.getRow(crefs[i].getRow());
Cell c = r.getCell(crefs[i].getCol());
// extract the cell contents based on cell type etc.
}

Excel formula not updating on row delete from java application using Apache POI

I'm using Apache POI in my application to write data to an excel file. I've an excel file template and a few formulas are also there in it. In my application, i use the excel template, write into it ,then delete unused rows and calculate formulas in the end. I'm using SUM formula in the file. The problem is when rows are deleted, the SUM formula is not updating,due to which error values are coming up in excel.
Example : the formula being used is : for cell B215 : SUM(B15:B214). in the application,after writing to the file i delete unused rows. now I've data till 70th row in the file.All other rows have been deleted. So my formula should get updated to : SUM(B15:B69) for cell B70. But in the file it's still showing the formula as SUM(B15:B214). Hence the value of that cell is "VALUE#
Code snippet :
File file = new File(path)
InputStream is = new FileInputStream(file)
POIFSFileSystem fs = new POIFSFileSystem(is)
HSSFWorkbook wb = new HSSFWorkbook(fs)
HSSFSheet excelSheet
int[] indexArray = populateSheet(excelSheet)
//indexArray is array with 3 values as startrow, lastrow, and first empty row.
removeBlankRows(excelSheet,indexArray)
//evaluate formula
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator()
for(HSSFRow r : excelSheet) {
for(HSSFCell c : r) {
if(c.getCellType() == Cell.CELL_TYPE_FORMULA) {
String formula = c.getCellFormula();
evaluator.evaluateFormulaCell(c)
}
}
}
private void removeBlankRows(HSSFSheet sheet, int[] shiftInfo){
for(int i = shiftInfo[2]; i <= shiftInfo[1]; ++i) {
sheet.removeRow(sheet.getRow(i))
}
//Shift up the rows
def startRow = shiftInfo[1]+1
def endRow = sheet.getLastRowNum()
def rowCount = -1* (shiftInfo[1] - shiftInfo[2] + 1)
sheet.shiftRows(startRow, endRow, rowCount)
}
This is an Excel bug. I've dealt with this in the past by doing the following:
Label the sum cell BSUM
We need a stable range that won't be affected by inserts/deletes.
Add a formula to a safe (one that won't get deleted) cell, for this example D15: ="B15:B"&ROW(BSUM)-1
This will produce a stable range.
Use INDIRECT in the BSUM cell like so:
=SUM(INDIRECT(D15))

Apache POI Excel - how to configure columns to be expanded?

I am using Apache POI API to generate excel spreadsheet to output some data.
The problem I am facing is when the spreadsheet is created and opened, columns are not expanded so that some long text like Date formatted text is not showing up on first glance.
I could just double click the column border in excel to expand or drag the border to adjust the column width but there could be 20+ columns and there is no way I want to do that manually every time I open the spreadsheet :(
I found out (though could be wrong method) groupRow() and setColumnGroupCollapsed() might be able to do the trick but no luck. Maybe I'm using it in wrong way.
Sample Code snippet
Workbook wb = new HSSFWorkbook();
CreationHelper createHelper = wb.getCreationHelper();
//create sheet
Sheet sheet = wb.createSheet("masatoSheet");
//not really working yet.... :(
//set group for expand/collapse
//sheet.groupRow(0, 10); //just random fromRow toRow argument values...
//sheet.setColumnGroupCollapsed(0, true);
//create row
Row row = sheet.createRow((short)0);
//put a cell in the row and store long text data
row.createCell(0).setCellValue("Loooooooong text not to show up first");
When this spreadsheet is created, the "Looooooong text not to show up first" string is in the cell but since the column is not expanded only "Loooooooo" is showing up.
How can I configure it so that when I open my spreadsheet, the column is already expanded???
After you have added all your data to the sheet, you can call autoSizeColumn(int column) on your sheet to autofit the columns to the proper size
Here is a link to the API.
See this post for more reference
Problem in fitting the excel cell size to the size of the content when using apache poi
Tip : To make Auto size work , the call to sheet.autoSizeColumn(columnNumber) should be made after populating the data into the excel.
Calling the method before populating the data, will have no effect.
If you want to auto size all columns in a workbook, here is a method that might be useful:
public void autoSizeColumns(Workbook workbook) {
int numberOfSheets = workbook.getNumberOfSheets();
for (int i = 0; i < numberOfSheets; i++) {
Sheet sheet = workbook.getSheetAt(i);
if (sheet.getPhysicalNumberOfRows() > 0) {
Row row = sheet.getRow(sheet.getFirstRowNum());
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
int columnIndex = cell.getColumnIndex();
sheet.autoSizeColumn(columnIndex);
}
}
}
}
You can try something like this:
HSSFSheet summarySheet = wb.createSheet();
summarySheet.setColumnWidth(short column, short width);
Here params are:column number in sheet and its width
But,the units of width are pretty small, you can try 4000 for example.
For Excel POI:
sheetName.autoSizeColumn(cellnum);
sample code below
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("your sheet name");
HSSFRow row = sheet.createRow(0);
cell = row.createCell(0);
cell.setCellValue("A BIG NAME WITH AUTO SIZE FEATURE ENABLED");
//this is crucial
sheet.autoSizeColumn(0);
//argument must be cell number
cell = row.createCell(1);
cell.setCellValue("a big name without auto size feature enabled");
Check the output and go nuts :)
If you know the count of your columns (f.e. it's equal to a collection list). You can simply use this one liner to adjust all columns of one sheet (if you use at least java 8):
IntStream.range(0, columnCount).forEach(sheet::autoSizeColumn)
You can add this, after your loop.
for (int i = 0; i<53;i++) {
sheet.autoSizeColumn(i);
}
I use below simple solution:
This is your workbook and sheet:
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("YOUR Workshhet");
then add data to your sheet with columns and rows. Once done with adding data to sheet write following code to autoSizeColumn width.
for (int columnIndex = 0; columnIndex < 15; columnIndex++) {
sheet.autoSizeColumn(columnIndex);
}
Here, instead 15, you add the number of columns in your sheet.
Hope someone helps this.
You can use setColumnWidth() if you want to expand your cell more.
Its very simple, use this one line code
dataSheet.autoSizeColumn(0)
or give the number of column in bracket
dataSheet.autoSizeColumn(cell number )
You can wrap the text as well. PFB sample code:
CellStyle wrapCellStyle = new_workbook.createCellStyle();
wrapCellStyle.setWrapText(true);

Categories