[英]Java POI : How to read Excel cell value and not the formula computing it?
我正在使用 Apache POI API 从 Excel 文件中获取值。 除了包含公式的单元格外,一切都很好。 事实上, cell.getStringCellValue()
返回的是单元格中使用的公式,而不是单元格的值。
我尝试使用evaluateFormulaCell()
方法,但它不起作用,因为我使用的是 GETPIVOTDATA Excel 公式,而此公式未在 API 中实现:
Exception in thread "main" org.apache.poi.ss.formula.eval.NotImplementedException: Error evaluating cell Landscape!K11
at org.apache.poi.ss.formula.WorkbookEvaluator.addExceptionInfo(WorkbookEvaluator.java:321)
at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:288)
at org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:221)
at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateFormulaCellValue(HSSFFormulaEvaluator.java:320)
at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateFormulaCell(HSSFFormulaEvaluator.java:213)
at fromExcelToJava.ExcelSheetReader.unAutreTest(ExcelSheetReader.java:193)
at fromExcelToJava.ExcelSheetReader.main(ExcelSheetReader.java:224)
Caused by: org.apache.poi.ss.formula.eval.NotImplementedException: GETPIVOTDATA
at org.apache.poi.hssf.record.formula.functions.NotImplementedFunction.evaluate(NotImplementedFunction.java:42)
对于公式单元格,excel 存储两件事。 一个是公式本身,另一个是“缓存”值(论坛被评估为的最后一个值)
如果您想获取最后一个缓存的值(这可能不再正确,但只要 Excel 保存了文件并且您没有更改它应该是),您将需要以下内容:
for(Cell cell : row) {
if(cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
System.out.println("Formula is " + cell.getCellFormula());
switch(cell.getCachedFormulaResultType()) {
case Cell.CELL_TYPE_NUMERIC:
System.out.println("Last evaluated as: " + cell.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
System.out.println("Last evaluated as \"" + cell.getRichStringCellValue() + "\"");
break;
}
}
}
以前发布的解决方案对我不起作用。 cell.getRawValue()
返回与单元格中所述相同的公式。 以下功能对我有用:
public void readFormula() throws IOException {
FileInputStream fis = new FileInputStream("Path of your file");
Workbook wb = new XSSFWorkbook(fis);
Sheet sheet = wb.getSheetAt(0);
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
CellReference cellReference = new CellReference("C2"); // pass the cell which contains the formula
Row row = sheet.getRow(cellReference.getRow());
Cell cell = row.getCell(cellReference.getCol());
CellValue cellValue = evaluator.evaluate(cell);
switch (cellValue.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
System.out.println(cellValue.getBooleanValue());
break;
case Cell.CELL_TYPE_NUMERIC:
System.out.println(cellValue.getNumberValue());
break;
case Cell.CELL_TYPE_STRING:
System.out.println(cellValue.getStringValue());
break;
case Cell.CELL_TYPE_BLANK:
break;
case Cell.CELL_TYPE_ERROR:
break;
// CELL_TYPE_FORMULA will never happen
case Cell.CELL_TYPE_FORMULA:
break;
}
}
如果需要从 Excel 表中读取值并将它们作为字符串,例如将它们显示在某处或以文本文件格式使用它们,那么使用DataFormatter
将是最好的。
DataFormatter
能够从每个单元格值中获取一个字符串,无论单元格值本身是字符串、boolean、数字、错误还是日期。 然后,此字符串看起来与 Excel 相同,将在其 GUI 的单元格中显示它。
唯一的问题是公式单元格。 在 apache poi 5.1.0 之前,需要一个 FormulaEvaluator 在使用 DataFormatter 时评估公式。 当apache poi
无法评估公式时,此操作失败。 从 5.2.0 开始, DataFormatter
可以设置为使用公式单元格的缓存值。 如果 Excel 之前已经计算过公式,则不需要计算公式。
完整示例:
import org.apache.poi.ss.usermodel.*;
import java.io.FileInputStream;
class ReadExcel {
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("./ExcelExample.xlsx"));
// up to apache poi 5.1.0 a FormulaEvaluator is needed to evaluate the formulas while using DataFormatter
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
DataFormatter dataFormatter = new DataFormatter(new java.util.Locale("en", "US"));
// from 5.2.0 on the DataFormatter can set to use cached values for formula cells
dataFormatter.setUseCachedValuesForFormulaCells(true);
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
//String value = dataFormatter.formatCellValue(cell, evaluator); // up to apache poi 5.1.0
String value = dataFormatter.formatCellValue(cell); // from apache poi 5.2.0 on
System.out.println(value);
}
}
workbook.close();
}
}
有一个替代命令,您可以在其中获取放置公式的单元格的原始值。 它的返回类型是字符串。 用:
cell.getRawValue();
如果要从 HSSF 单元中提取原始值,可以使用如下代码片段:
CellBase base = (CellBase) cell;
CellType cellType = cell.getCellType();
base.setCellType(CellType.STRING);
String result = cell.getStringCellValue();
base.setCellType(cellType);
至少对于完全由数字组成的字符串(并由 Excel 自动转换为数字),这将返回原始字符串(例如"12345"
)而不是小数值(例如"12345.0"
)。 请注意, setCellType
在接口Cell
可用(自 v. 4.1 起)但已弃用并宣布在 v 5.x 中被淘汰,而该方法在类CellBase
仍然可用。 显然,在Cell
接口中使用getRawValue
或者至少能够在非 STRING 单元格类型上使用getStringCellValue
会更好。 不幸的是,描述中提到的setCellType
所有替换都不会涵盖这个用例(也许 POI 开发团队的成员阅读了这个答案)。
SelThroughJava 的回答非常有帮助,我必须对我的代码进行一些修改才能工作。 我使用https://mvnrepository.com/artifact/org.apache.poi/poi和https://mvnrepository.com/artifact/org.testng/testng作为依赖项。 下面给出了完整的代码,并带有精确的导入。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.sl.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ReadExcelFormulaValue {
private static final CellType NUMERIC = null;
public static void main(String[] args) {
try {
readFormula();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void readFormula() throws IOException {
FileInputStream fis = new FileInputStream("C:eclipse-workspace\\sam-webdbriver-diaries\\resources\\tUser_WS.xls");
org.apache.poi.ss.usermodel.Workbook workbook = WorkbookFactory.create(fis);
org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(0);
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
CellReference cellReference = new CellReference("G2"); // pass the cell which contains the formula
Row row = sheet.getRow(cellReference.getRow());
Cell cell = row.getCell(cellReference.getCol());
CellValue cellValue = evaluator.evaluate(cell);
System.out.println("Cell type month is "+cellValue.getCellTypeEnum());
System.out.println("getNumberValue month is "+cellValue.getNumberValue());
// System.out.println("getStringValue "+cellValue.getStringValue());
cellReference = new CellReference("H2"); // pass the cell which contains the formula
row = sheet.getRow(cellReference.getRow());
cell = row.getCell(cellReference.getCol());
cellValue = evaluator.evaluate(cell);
System.out.println("getNumberValue DAY is "+cellValue.getNumberValue());
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.