Apache poi 在读取 excel 文件时的奇怪行为
Strange behaviour by Apache poi while reading excel file
我已经使用 Apache POI 库成功读取了 excel 文件。但是,我从它那里收到了一种奇怪的行为,我不确定为什么会这样。
如果我创建一个新的 excel 文件并调整所需的数据,就像这样:
设置在电子邮件列第一个的空单元格根本没有被读取(忽略)。
但是如果我修改文件并更改同一文件的字体或字体大小,Apache POI 会成功读取空电子邮件单元格。
默认字体设置(空单元格未读):
我从方法中收到的数组:
[Hari Krishna, 445444, 986544544]
更改字体大小(成功读取空白单元格):
我从方法中收到的数组:
[Hari Krishna, 445444, 986544544, ]
这是我用来通读 excel 文件的完整代码:
public static List importExcelFile(String filePath, String fileName) {
DataFormatter formatter = new DataFormatter(Locale.UK);
// stores data from excel file
List excelDataList = new ArrayList();
try {
// Import file from source destination
FileInputStream file = new FileInputStream(new File(filePath.concat(File.separator.concat(fileName))));
// Get the workbook instance for XLS file
XSSFWorkbook workbook = new XSSFWorkbook(file);
// workbook.setMissingCellPolicy(Row.RETURN_BLANK_AS_NULL);
// Get first sheet from the workbook
XSSFSheet sheet = workbook.getSheetAt(0);
// Iterate through each rows from first sheet
Iterator<Row> rowIterator = sheet.iterator();
// Skip first row, since it is header row
rowIterator.next();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
int nextCell = 1;
int currentCell = 0;
// add data of each row
ArrayList rowList = new ArrayList();
// For each row, iterate through each columns
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
currentCell = cell.getColumnIndex();
if (currentCell >= nextCell) {
int diffInCellCount = currentCell - nextCell;
for (int nullLoop = 0; nullLoop <= diffInCellCount; nullLoop++) {
rowList.add(" ");
nextCell++;
}
}
switch (cell.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
rowList.add(cell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
String date = formatter.formatCellValue(cell);
rowList.add(date);
} else {
rowList.add(cell.getNumericCellValue());
}
break;
case Cell.CELL_TYPE_STRING:
rowList.add(cell.getStringCellValue());
break;
case Cell.CELL_TYPE_BLANK:
rowList.add(" ");
break;
case Cell.CELL_TYPE_ERROR:
rowList.add(" ");
break;
default:
break;
}
nextCell++;
}
excelDataList.add(rowList);
}
file.close();
} catch (FileNotFoundException e) {
System.out.println(e.toString());
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return excelDataList;
}
原因是当您设置单元格的字体大小时,Excel 需要一种方法来知道单元格具有不同的字体(通常,CellStyle
)。当您更改默认字体大小时,Excel 创建了一个空白单元格并为其指定了单元格样式 - 字体大小为 10。因为 CellStyle
是 Cell
的属性, Excel 需要一个 Cell
以便它可以存储 CellStyle
。
当您阅读带有 Iterator<Cell>
的 Cell
时,它只会 return 那些存在的 Cell
。在更改字体大小之前,"Hari Krishna" 的 "Email" 单元格不存在。更改字体大小后,现在 "Hari Krishna" 的 "Email" 单元格存在,即使它是空白的。
如果你想要空白值,即使没有字体大小变化,那么你不能使用Iterator
,因为它不会return那个Cell
——它不存在。您可以在 Row
对象上使用标准 for
循环,使用 MissingCellPolicy
of CREATE_NULL_AS_BLANK
.
如果你想跳过空白值,不管是否有字体大小变化,那么你应该简单地跳过类型为 CELL_TYPE_BLANK
的单元格。从您的 switch
语句中删除该案例。
我已经使用 Apache POI 库成功读取了 excel 文件。但是,我从它那里收到了一种奇怪的行为,我不确定为什么会这样。
如果我创建一个新的 excel 文件并调整所需的数据,就像这样:
设置在电子邮件列第一个的空单元格根本没有被读取(忽略)。
但是如果我修改文件并更改同一文件的字体或字体大小,Apache POI 会成功读取空电子邮件单元格。
默认字体设置(空单元格未读):
我从方法中收到的数组:
[Hari Krishna, 445444, 986544544]
更改字体大小(成功读取空白单元格):
我从方法中收到的数组:
[Hari Krishna, 445444, 986544544, ]
这是我用来通读 excel 文件的完整代码:
public static List importExcelFile(String filePath, String fileName) {
DataFormatter formatter = new DataFormatter(Locale.UK);
// stores data from excel file
List excelDataList = new ArrayList();
try {
// Import file from source destination
FileInputStream file = new FileInputStream(new File(filePath.concat(File.separator.concat(fileName))));
// Get the workbook instance for XLS file
XSSFWorkbook workbook = new XSSFWorkbook(file);
// workbook.setMissingCellPolicy(Row.RETURN_BLANK_AS_NULL);
// Get first sheet from the workbook
XSSFSheet sheet = workbook.getSheetAt(0);
// Iterate through each rows from first sheet
Iterator<Row> rowIterator = sheet.iterator();
// Skip first row, since it is header row
rowIterator.next();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
int nextCell = 1;
int currentCell = 0;
// add data of each row
ArrayList rowList = new ArrayList();
// For each row, iterate through each columns
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
currentCell = cell.getColumnIndex();
if (currentCell >= nextCell) {
int diffInCellCount = currentCell - nextCell;
for (int nullLoop = 0; nullLoop <= diffInCellCount; nullLoop++) {
rowList.add(" ");
nextCell++;
}
}
switch (cell.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
rowList.add(cell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
String date = formatter.formatCellValue(cell);
rowList.add(date);
} else {
rowList.add(cell.getNumericCellValue());
}
break;
case Cell.CELL_TYPE_STRING:
rowList.add(cell.getStringCellValue());
break;
case Cell.CELL_TYPE_BLANK:
rowList.add(" ");
break;
case Cell.CELL_TYPE_ERROR:
rowList.add(" ");
break;
default:
break;
}
nextCell++;
}
excelDataList.add(rowList);
}
file.close();
} catch (FileNotFoundException e) {
System.out.println(e.toString());
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return excelDataList;
}
原因是当您设置单元格的字体大小时,Excel 需要一种方法来知道单元格具有不同的字体(通常,CellStyle
)。当您更改默认字体大小时,Excel 创建了一个空白单元格并为其指定了单元格样式 - 字体大小为 10。因为 CellStyle
是 Cell
的属性, Excel 需要一个 Cell
以便它可以存储 CellStyle
。
当您阅读带有 Iterator<Cell>
的 Cell
时,它只会 return 那些存在的 Cell
。在更改字体大小之前,"Hari Krishna" 的 "Email" 单元格不存在。更改字体大小后,现在 "Hari Krishna" 的 "Email" 单元格存在,即使它是空白的。
如果你想要空白值,即使没有字体大小变化,那么你不能使用Iterator
,因为它不会return那个Cell
——它不存在。您可以在 Row
对象上使用标准 for
循环,使用 MissingCellPolicy
of CREATE_NULL_AS_BLANK
.
如果你想跳过空白值,不管是否有字体大小变化,那么你应该简单地跳过类型为 CELL_TYPE_BLANK
的单元格。从您的 switch
语句中删除该案例。