Is there any particular reason POI creates a numeric cell when in fact, it's actually empty? What happens is that by the time I get to that cell I obviously get an runtime error as I can't get the string value (it's a numeric cell, after all) and I can't get the numeric value either (can't get a number from an empty string) so my 2 questions would be:
How does POI got there?
Is there any way I can handle this scenario without having to explicitly go to my excel file?
UPDATE I:
After reading / parsing my excel file, POI generates the following XML for this particular cell:
<x:c r="AA2" t="n">
<x:v/>
</x:c>
My method is something like this:
final FileInputStream inputStream = new FileInputStream(new File("PATH/TO/FILE.xml"));
final XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
final XSSFSheet sheet = workbook.getSheet("SHEET_NAME");
final int columnCount = sheet.getRow(0).getLastCellNum();
for (int rowNumber = 0; rowNumber <= sheet.getLastRowNum(); rowNumber++)
{
final XSSFRow row = sheet.getRow(rowNumber);
for (int column = 0; column < columnCount; column++)
{
// By now my cell would throw an exception if I attempt cell.getStringCellValue() or cell.getNumericCellValue() as cell.getCellType() returns "0" / NUMERIC
final XSSFCell cell = row.getCell(column);
...
}
}
I was thinking about adding an additional validation to determine whether the cell is empty by using the getRawValue() method, but not sure if there's a better way to handle this as it was obviously wrongly parsed.
UPDATE II
I've been able to reproduce this scenario by doing adding this as part of a unit test (I still don't understand why POI would fall into this scenario though):
final XLSXSheetConverterImpl xlsxSheetConverter = new XLSXSheetConverterImpl();
xlsxSheetConverter.setSheetName(SHEET_NAME);
xlsxSheetConverter.setFilePrefix(FILE_PREFIX);
XSSFWorkbook workbook = new XSSFWorkbook();
final XSSFSheet sheet = workbook.createSheet(SHEET_NAME);
final XSSFRow row = sheet.createRow(0);
XSSFCell cell = row.createCell(0);
final CTCellImpl ctCell = (CTCellImpl) cell.getCTCell();
ctCell.setT(STCellType.N);
ctCell.setV("");
Thanks in advance!
This is a known bug in older POI versions, see: https://bz.apache.org/bugzilla/show_bug.cgi?id=56702
It's been fixed since 3.11 version
Thank you all for your help!!
Related
I am still new to Java trying only to loop over an excel column.
The Excel sheet:
I want to have in HashMap or Array so that I can compare these dates later on with another column.
My Code is giving me yet a string as you see in the screenshot:
How can I change this String to a another Data structure to access the "index" of the values. Something like dates.get(0) --> So 01-Jul-2018. I would change the time format later.
The Code section:
XSSFWorkbook workbook = new XSSFWorkbook(fsIP);
XSSFSheet sheet = workbook.getSheetAt(0);
for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
Row row = sheet.getRow(rowIndex);
if (row != null) {
Cell cell = row.getCell(0); // getColumn(0)
if (cell != null) {
System.out.print(cell);
}
}
}
What would you like to know further from me?
I would be thankful for every help!
I'm using Apache POI 3.17 to read some excel data. My second column (index of 1 because of 0 index) is empty and I want to be able to read it, but can't get my code to read the cell as empty. I have this which isn't working:
Cell c = row.getCell(1, Row.RETURN_BLANK_AS_NULL);
if (c == null) {
// do whatever
}
But the second parameter can't be taken in. I get "RETURN_BLANK_AS_NULL cannot be resolved or is not a field"
The constants in the Row class itself were deprecated as of POI-3.15-beta2, marked for removal as of POI-3.17. This diff shows when those constants were deprecated in June 2016. They were removed in 3.17.
Before 3.17, the enum Row.MissingCellPolicy was already defined as a replacement. If you're using 3.17, then you must use that enum; it is defined as a member of the Row interface. Try
Cell c = row.getCell(1, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
Try using org.apache.poi.ss.usermodel.DataFormatter.
DataFormatter formatter = new DataFormatter();
Workbook workbook = WorkbookFactory.create(new File("yourFileName.xls"));
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
for(Cell cell : row)
{
String text = formatter.formatCellValue(cell);
System.out.println(text);
}
}
workbook.close();
Edit - thanks for responses. Have made changes and as suggested found the problem was a NOW on empty rows.
I am writing a program that loads various excel sheets and provides an output based on certain criteria. See code below. My problem is that the code does not write or save to the DISPLAY sheet. I realise the code below is not particularly neat but have copy pasted to check if I can get anything to save. If I comment out everything within the loop and try to write to the cell at the end before I save, it works and shows in the sheet. If I don't comment out the data formatter part it doesn't work even when trying to write to cell just before the part where I am saving output file. I am guessing the problem is caused by the data formatter, but I can't work out why.
public void checkForChanges() {
try {
FileInputStream fsIP = new FileInputStream("Change.xls");
HSSFWorkbook fWorkbook = new HSSFWorkbook(fsIP);
HSSFSheet recipeSheet = fWorkbook.getSheet("RECIPE STEPS");
HSSFSheet fromSheet = fWorkbook.getSheet("FROM FORMAT");
HSSFSheet toSheet = fWorkbook.getSheet("TO FORMAT");
HSSFSheet displaySheet = fWorkbook.getSheet("DISPLAY");
for (int i = 0; i < 30; i++) {
DataFormatter recipeFormatter = new DataFormatter();
HSSFRow recipeRow = recipeSheet.getRow(i);
HSSFCell recipeCellsColumnA = recipeRow.getCell(0);
String recipeCellValueColumnA = recipeFormatter.formatCellValue(recipeCellsColumnA);
System.out.println(recipeCellValueColumnA);
HSSFCell recipeCellsColumnB = recipeRow.getCell(1);
String recipeCellValueColumnB = recipeFormatter.formatCellValue(recipeCellsColumnB);
System.out.println(recipeCellValueColumnB);
DataFormatter fromFormatter = new DataFormatter();
HSSFRow fromRow = fromSheet.getRow(i);
HSSFCell fromCells = fromRow.getCell(0);
String fromCellValue = fromFormatter.formatCellValue(fromCells);
System.out.println(fromCellValue);
DataFormatter toFormatter = new DataFormatter();
HSSFRow toRow = toSheet.getRow(i);
HSSFCell toCells = toRow.getCell(0);
String toCellValue = toFormatter.formatCellValue(toCells);
System.out.println(toCellValue);
if (recipeCellValueColumnB.equals("YES") && !fromCellValue.equals(toCellValue)) {
System.out.println("PUT VALUE FROM 'TO FORMAT' COLUMN A ROW I INTO 'DISPLAY' SHEET CELL COLUMN B ROW I");
System.out.println("PUT VALUE FROM 'RECIPE STEPS' COLUMN A ROW I INTO 'DISPLAY' SHEET CELL COLUMN A ROW I");
Row row = displaySheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue("TEST");
} else if (recipeCellValueColumnB.equals("YES") && fromCellValue.equals(toCellValue)) {
System.out.println("SET CELL IN 'DISPLAY' SHEET COLUMN A ROW I TO '' ");
System.out.println("SET CELL IN 'DISPLAY' SHEET COLUMN B ROW I TO '' ");
Row row = displaySheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue("TEST");
} else if (recipeCellValueColumnB.equals("NO")) {
System.out.println("PUT VALUE FROM 'TO FORMAT' COLUMN A ROW I INTO 'DISPLAY' SHEET CELL COLUMN B ROW I");
System.out.println("PUT VALUE FROM 'RECIPE STEPS' COLUMN A ROW I INTO 'DISPLAY' SHEET CELL COLUMN A ROW I");
Row row = displaySheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue("TEST");
}else if (recipeCellValueColumnA.equals("Step Name") && recipeCellValueColumnB.equals("Always Compare?")) {
System.out.println("SET CELL IN DISPLAY COLUMN A ROW I TO 'REQUIRED STEPS'");
System.out.println("PUT VALUE FROM 'TO FORMAT' COLUMN A ROW I INTO 'DISPLAY' SHEET CELL COLUMN B ROW I");
Row row = displaySheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue("TEST");
}
}
FileOutputStream output_file = new FileOutputStream(new File("Change.xls"));
BufferedOutputStream bos = new BufferedOutputStream(output_file);
fWorkbook.write(output_file);
fWorkbook.close();
bos.close();
output_file.close();
}catch(Exception e){
}
}
Sorry for any poor explanation, it's late and I'm tired and frustrated!
Thanks
The problem with your code is this:
catch(Exception e)
{
}
This is saying "don't tell me about any exceptions". This is exception squashing ... and it is horrible, and lazy, and just plain wrong.
Somewhere in your code there is probably something that is either throwing an exception directly, or causing POI (or something) to throw an exception. That's a bug. But your horrible exception squashing is throwing away the evidence that will allow you to identify and then fix the bug.
I am guessing the problem is caused by the data formatter, but I can't work out why.
It could be many things ... including something daft like an NPE or a passing an out-of-range index of an incorrect filename.
Solution:
Get rid of the try catch, and allow the exceptions to propagate to the caller.
In the caller (or further up the stack) handle unexpected exceptions by printing or logging a stacktrace and causing the application to fail.
Run the modified program.
When it fails (at it probably will), read the exception message and stacktrace and work out what the underlying problem is; i.e the problam that your horrible exception squashing is hiding.
Then remember to NEVER squash all exceptions like that, in Java or in any other programming language.
(It is sometimes OK to squash a specific exception in a specific context ... but only after carefully analyzing the code to ensure that that you won't squash other (unexpected) exceptions at the same time.)
I am using Apache POI to import data from excel file to database.(newbie to APACHE POI)
In which I am allowing user to select columns from excel sheet and Map those columns to the Database columns. After mapping the columns, when I try to insert the records from Excel to Database then:
If Columns with NO blank values in them are Mapped then Proper data is inserted into the database
If columns are Mapped with BLANK values in them, then if a Excel Cell has blank value then previous value of that column is assigned.
Source Code:
FileInputStream file = new FileInputStream(new File("C:/Temp.xls"));
HSSFWorkbook workbook = new HSSFWorkbook(file); //Get the workbook instance for XLS file
HSSFSheet sheet = workbook.getSheetAt(0); //Get first sheet from the workbook
Iterator<Row> rowIterator = sheet.iterator(); //Iterate through each rows from first sheet
while (rowIterator.hasNext())
{
HSSFRow hssfRow = (HSSFRow) rowIterator.next();
Iterator<Cell> iterator = hssfRow.cellIterator();
int current = 0, next = 1;
while (iterator.hasNext())
{
HSSFCell hssfCell = (HSSFCell) iterator.next();
current = hssfCell.getColumnIndex();
for(int i=0;i<arrIndex.length;i++) //arrayIndex is array of Excel cell Indexes selected by the user
{
if(arrIndex[i] == hssfCell.getColumnIndex())
{
if(current<next)
{
//System.out.println("Condition Satisfied");
}
else
{
System.out.println( "pstmt.setString("+next+",null);");
pstmt.setString(next,null);
next = next + 1;
}
System.out.println( "pstmt.setString("+next+","+((Object)hssfCell).toString()+");");
pstmt.setString(next,((Object)hssfCell).toString());
next = next + 1;
}
}
}
pstmt.addBatch();
}
I have look for similar questions on SO, but still not able to solve the issue.. So any help will be appreciated.
Thanks in advance..
You've made a very common mistake, which has been covered in rather a lot of past StackOverflow questions
As the Apache POI documentation on cell iterating says
In some cases, when iterating, you need full control over how missing or blank cells are treated, and you need to ensure you visit every cell and not just those defined in the file. (The CellIterator will only return the cells defined in the file, which is largely those with values or stylings, but it depends on Excel).
It sounds like you are in that situation, where you need to care about hitting every row/cell, and not just grabbing all the available cells without worrying about the gaps
You'll want to change you code to look somewhat like the example in the POI docs:
// Decide which rows to process
int rowStart = Math.min(15, sheet.getFirstRowNum());
int rowEnd = Math.max(1400, sheet.getLastRowNum());
for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
Row r = sheet.getRow(rowNum);
int lastColumn = Math.max(r.getLastCellNum(), MY_MINIMUM_COLUMN_COUNT);
for (int cn = 0; cn < lastColumn; cn++) {
Cell c = r.getCell(cn, Row.RETURN_BLANK_AS_NULL);
if (c == null) {
// The spreadsheet is empty in this cell
// Mark it as blank in the database if needed
} else {
// Do something useful with the cell's contents
}
}
}
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);