I am using the Apache POI library to read values from an Excel sheet into a Java program.
I iterate through each row of a table to get the values I need.
Within the object Row, there is a TreeMap that contains XSSFCell objects as values.
Normally I get the following TreeMap:
Where key 4 is included. The value often is an empty string as chosen in this picture.
For some reason, for some objects I get the following TreeMap:
Where the key 4 is missing.
Both Row Objects belong to the same table.
This is how I use my object Row:
XSSFSheet mySheet = myWorkBook.getSheet("nameOfSheet");
Iterator<Row> rowIterator = mySheet.iterator();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
// here I call my method
}
You can prevent this from causing inconsistency in your application by calling "getCell()" passing in both an index and a MissingCellPolicy, probably Row.RETURN_BLANK_AS_NULL.
The Apache POI guide explains:
In some cases, when iterating, you need full control over how missing
or blank rows and 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).
In cases such as these, you should fetch the first and last column
information for a row, then call getCell(int, MissingCellPolicy) to
fetch the cell. Use a MissingCellPolicy to control how blank or null
cells are handled.
// 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);
if (r == null) {
// This whole row is empty
// Handle it as needed
continue;
}
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
} else {
// Do something useful with the cell's contents
}
}
}
I need to remove several lines of an excel xls sheet.
These lines always contain the same first cell thats why i check the first cell of all rows to find these rows
SSFCell myCell = myRow.getCell(0);
myCell.setCellType(Cell.CELL_TYPE_STRING);
String foundString = myCell.getStringCellValue();
if(foundString.equals(searchString)){
foundRows.add(rowCount);
}
rowCount++;
I then go on and "remove" those rows using removeRow which nulls all values
public static void removeRows() {
List<Integer> foundRowsToDelete = new ArrayList<Integer>();
//Copy values to another list
for(int i=0; i<foundRows.size(); i++){
foundRowsToDelete.add(foundRows.get(i));
}
//Delete values from rows, leaving empty rows
while(foundRowsToDelete.size()!=0){
int rowIndex = foundRowsToDelete.get(0);
Row removingRow = mySheet.getRow(rowIndex);
if (removingRow != null) {
mySheet.removeRow(removingRow);
foundRowsToDelete.remove(0);
}
}
//Move empty rows to bottom of the sheet
for(int i = 0; i < mySheet.getLastRowNum(); i++){
if(isRowEmpty(i)){
mySheet.shiftRows(i+1, mySheet.getLastRowNum(), -1);
i--;
}
}
}
I check if they are empty through using the duplicated rowcounter
//Comparision of previously detected empty rows and given row count
public static boolean isRowEmpty(int suspectedRowNumber) {
for(int i=0;i<foundRows.size();i++){
if (suspectedRowNumber == foundRows.get(i)){
foundRows.remove(i);
return true;
}
}
return false;
}
However only the first of these rows gets deleted. The rest will stay empty.
I therefore assume that there is something wrong with some incrementing done by me, but i just can't figure out exactly why.
Thanks for your help in advance.
It's not immediately clear why your code isn't working, but I look at a couple things to debug
Your foundRowsToDelete ArrayList is being populated with values contained in the foundRows Array. Are you sure what you expect to find in foundRows is actually there.
Is there a reason you don't remove the row when initally iterating through the rows in your sheet? Maybe something like this:
Sheet sheet = workbook.getSheetAt(0);
For (Row row : sheet) {
SSFCell myCell = row.getCell(0);
if(myCell.getCellType() == Cell.CELL_TYPE_STRING){
String foundString = myCell.getStringCellValue();
if(foundString.equalsIgnoreCase(searchString){
// why not just remove here?
sheet.removeRow(row);
}
}
}
}
I am extremely new to using Apache POI (and still new to Java too, infact!) and have come across an exception that I cannot determine how to fix.
Obviously you cannot store 2 different datatypes in an array, so I selected every column with data and converted the cell format to "Text" in Excel.
I then try to store this data in an array with the following:
String cellData[][] = new String[rows][cols];
System.out.println(rows+" entries found with "+cols+" columns of data");
//iterate over every row and store cell data;
for(int i=0; i<rows; i++){
row = worksheet.getRow(i);
if(row != null){
for(int j=0;j<cols;j++){
cell = row.getCell(j);
if(cell != null){
try{
cellData[i][j] = cell.getStringCellValue();
}catch(IllegalStateException e){
System.out.println("Cell data is not a string(text)");
}
}
}
}
}
The output from this is countless rows of "Cell data is not a string(text)", where am I going wrong here? Forgive me for any oversights I am also new to Stackoverflow and want to become a valued member of the community here too :) Thanks for your advice!
EDIT: Added e.printStackTrace() as requested.
at exceltesting.ExcelTesting.main(ExcelTesting.java:80)
java.lang.IllegalStateException: Cannot get a text value from a numeric cell
at org.apache.poi.hssf.usermodel.HSSFCell.typeMismatch(HSSFCell.java:648)
at org.apache.poi.hssf.usermodel.HSSFCell.getRichStringCellValue(HSSFCell.java:725)
at org.apache.poi.hssf.usermodel.HSSFCell.getStringCellValue(HSSFCell.java:708)
Interestingly enough, when I change it from cell.getStringCellValue() to cell.getNumericCellValue() the IllegalStateException then changes to "Cannot get a numerical value from a text cell"... I think the excel document, despite converting the cells to text is not actually changing to string data and passing them as their inherent data type? Thanks again
It seems that some of the cells are of Numeric type and some of them are of String Type. You need to handle Numeric Cell Types and String Cell types separately. I have not checked on my end, but sure... the following will work.
Cell cell = row.getCell(j);
CellValue cellValue = evaluator.evaluate(cell);
switch (cellValue.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:
cellData[i][j] = String.valueOf(cellValue.getNumberValue());
break;
case Cell.CELL_TYPE_STRING:
cellData[i][j] = cell.getStringCellValue();
break
}
When trying to read an Excel sheet I get an exception if some cell is empty:
Cell[] rowCells = sheet.getRow(1);
or
Cell cell = sheet.getCell(0,1);
I always get the same message:
java.lang.ArrayIndexOutOfBoundsException: 1
at jxl.read.biff.SheetImpl.getCell(SheetImpl.java:356)
at gui.ReadExcel.read(ReadExcel.java:45)
at gui.GUIcontroller.chooseSaveFile(GUIcontroller.java:101)
What is the problem? How can I know if the cell is empty, so I won't copy its value?
You can use the getRows or getColumns method to check the bounds of the sheet. The ArrayIndexOutOfBoundsException occurs because you are trying to access a value, which is beyond the range of the farthest cell which is not empty.
int rows = sheet.getRows();
int columns = sheet.getColumns();
int i = 1;
if(i<rows)
Cell[] rowCells = sheet.getRow(i); //Won't throw an Exception
if(i<rows && j<columns)
Cell cell = sheet.getCell(i,j);
In this case you can't read the cell because, as far as jxl is concerned, it doesn't really exist on the spreadsheet. It has yet to be created so there is really no cell to get. It may sound odd because excel sheets go on for what seems like forever though it doesn't store the data of all these empty cells because the file size would be huge. So when jxl goes to read the data it will simply tell you there is nothing there.
If you want to read the cells and all your cells are grouped together than you could try:
int width = sheet.getColumns();
int height = sheet.getRows();
List<Cell> cells = new ArrayList<Cell>();
for(int i=0; i<width; i++){
for(int j=0; j<height; j++){
cells.add(sheet.getCell(i, j));
}
}
If they're not grouped together and your not sure which cells maybe empty there is still a fairly simple solution
List<Cell> cells = new ArrayList<Cell>();
Cell cell = null;
try{
cell = sheet.getCell(0, 1);
}catch(Exception e){
e.printStackTrace();
}finally{
if(cell != null){
cells.add(cell);
}
}
This way you can safely attempt to read a cell and throw it away if it doesn't contain anything.
I hope this is what you were looking for.
I am taking input from an excel sheet using Poi.jar and wanted to know how to check if a cell is empty or not.
Right now I m using the below code.
cell = myRow.getCell(3);
if (cell != null) {
cell.setCellType(Cell.CELL_TYPE_STRING);
//System.out.print(cell.getStringCellValue() + "\t\t");
if (cell.getStringCellValue() != "")
depend[p] = Integer.parseInt(cell.getStringCellValue());
}
}
If you're using Apache POI 4.x, you can do that with:
Cell c = row.getCell(3);
if (c == null || c.getCellType() == CellType.Blank) {
// This cell is empty
}
For older Apache POI 3.x versions, which predate the move to the CellType enum, it's:
Cell c = row.getCell(3);
if (c == null || c.getCellType() == Cell.CELL_TYPE_BLANK) {
// This cell is empty
}
Don't forget to check if the Row is null though - if the row has never been used with no cells ever used or styled, the row itself might be null!
Gagravarr's answer is quite good!
Check if an excel cell is empty
But if you assume that a cell is also empty if it contains an empty String (""), you need some additional code. This can happen, if a cell was edited and then not cleared properly (for how to clear a cell properly, see further below).
I wrote myself a helper to check if an XSSFCell is empty (including an empty String).
/**
* Checks if the value of a given {#link XSSFCell} is empty.
*
* #param cell
* The {#link XSSFCell}.
* #return {#code true} if the {#link XSSFCell} is empty. {#code false}
* otherwise.
*/
public static boolean isCellEmpty(final XSSFCell cell) {
if (cell == null) { // use row.getCell(x, Row.CREATE_NULL_AS_BLANK) to avoid null cells
return true;
}
if (cell.getCellType() == Cell.CELL_TYPE_BLANK) {
return true;
}
if (cell.getCellType() == Cell.CELL_TYPE_STRING && cell.getStringCellValue().trim().isEmpty()) {
return true;
}
return false;
}
Pay attention for newer POI Version
They first changed getCellType() to getCellTypeEnum() as of Version 3.15 Beta 3 and then moved back to getCellType() as of Version 4.0.
Version >= 3.15 Beta 3:
Use CellType.BLANK and CellType.STRING instead of Cell.CELL_TYPE_BLANK and Cell.CELL_TYPE_STRING
Version >= 3.15 Beta 3 && Version < 4.0
Use Cell.getCellTypeEnum() instead of Cell.getCellType()
But better double check yourself, because they planned to change it back in future releases.
Example
This JUnit test shows the case in which the additional empty check is needed.
Scenario: the content of a cell is changed within a Java program. Later on, in the same Java program, the cell is checked for emptiness. The test will fail if the isCellEmpty(XSSFCell cell) function doesn't check for empty Strings.
#Test
public void testIsCellEmpty_CellHasEmptyString_ReturnTrue() {
// Arrange
XSSFCell cell = new XSSFWorkbook().createSheet().createRow(0).createCell(0);
boolean expectedValue = true;
boolean actualValue;
// Act
cell.setCellValue("foo");
cell.setCellValue("bar");
cell.setCellValue(" ");
actualValue = isCellEmpty(cell);
// Assert
Assert.assertEquals(expectedValue, actualValue);
}
In addition: Clear a cell properly
Just in case if someone wants to know, how to clear the content of a cell properly. There are two ways to archive that (I would recommend way 1).
// way 1
public static void clearCell(final XSSFCell cell) {
cell.setCellType(Cell.CELL_TYPE_BLANK);
}
// way 2
public static void clearCell(final XSSFCell cell) {
String nullString = null;
cell.setCellValue(nullString);
}
Why way 1? Explicit is better than implicit (thanks, Python)
Way 1: sets the cell type explicitly back to blank.
Way 2: sets the cell type implicitly back to blank due to a side effect when setting a cell value to a null String.
Useful sources
Official Documentation
CellTypes
XSSFCell.setCellValue(String)
Cell.setCellType(CellType)
Regards winklerrr
As of Apache POI 3.17 you will have to check if the cell is empty using enumerations:
import org.apache.poi.ss.usermodel.CellType;
if(cell == null || cell.getCellTypeEnum() == CellType.BLANK) { ... }
Cell cell = row.getCell(x, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
This trick helped me a lot, see if it's useful for you
This is the safest and most concise way I see as of POI 3.1.7 up to POI 4:
boolean isBlankCell = CellType.BLANK == cell.getCellTypeEnum();
boolean isEmptyStringCell = CellType.STRING == cell.getCellTypeEnum() && cell.getStringCellValue().trim().isEmpty();
if (isBlankCell || isEmptyStringCell) {
...
As of POI 4 getCellTypeEnum() will be deprecated if favor of getCellType() but the return type should stay the same.
First to avoid NullPointerException you have to add this
Row.MissingCellPolicy.CREATE_NULL_AS_BLANK
This will create a blank cell instead of giving you NPE then you can check to make sure nothing went wrong just like what #Gagravarr have said.
Cell cell = row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
if (cell == null || cell.getCellTypeEnum() == CellType.BLANK)
// do what you want
Row.MissingCellPolicy.CREATE_NULL_AS_BLANK is work in my case.
total_colume = myRow.getLastCellNum();
int current_colume = 0;
HSSFCell ReadInCellValue;
while (current_colume <= total_colume) {
ReadInCellValue = myRow.getCell(current_colume, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);//if cell is empty, return black
if (ReadInCellValue.toString=="") Log.d("empty cell", "colume=" + String.valuOf(current_colume));
current_colume++;
}
There is one other option also .
row=(Row) sheet.getRow(i);
if (row == null || isEmptyRow(row)) {
return;
}
Iterator<Cell> cells = row.cellIterator();
while (cells.hasNext())
{}
.getCellType() != Cell.CELL_TYPE_BLANK
Cell.getCellType() is deprecated in the latest POI API. If you are using POI API version 3.17, use the below code:
if (Cell.getCellTypeEnum() == CellType.BLANK) {
//do your stuff here
}
You can also use switch case like
String columndata2 = "";
if (cell.getColumnIndex() == 1) {// To match column index
switch (cell.getCellType()) {
case Cell.CELL_TYPE_BLANK:
columndata2 = "";
break;
case Cell.CELL_TYPE_NUMERIC:
columndata2 = "" + cell.getNumericCellValue();
break;
case Cell.CELL_TYPE_STRING:
columndata2 = cell.getStringCellValue();
break;
}
}
System.out.println("Cell Value "+ columndata2);
Try below code:
String empty = "-";
if (row.getCell(3) == null || row.getCell(3).getCellType() == Cell.CELL_TYPE_BLANK) {
upld.setValue(empty);
} else {
upld.setValue(row.getCell(3).getStringCellValue());
}