尝试从具有Apache POI的Excel工作簿中获取公式时出错

我正在使用Apache POI来更改Excel文档中的某些值,然后从不同的单元格读取结果。 一切都很顺利,直到我从客户那里得到一个testing文件。 经过testing,我发现我有两个问题:

1)当我尝试从具有公式的单元格中获取值,但返回格式为货币的结果并以€符号作为前缀时,出现错误。

2)当我试图从一个单元格中引用另一个单元格的公式(例如:单元格B20中的单元格B20的值为“= Sheet 2!A20”,其中单元格2中的A20是一个SUM()公式),我得到一个错误。

错误是: Exception in thread "main" java.lang.IllegalStateException: Cannot get a numeric value from a error formula cell

文档名称,input列(值更改的地方)和输出列(读取值的地方)都是从命令行获取的。

你可以find我的代码咆哮:

 package poitest; import java.util.List; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.CellReference; import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.usermodel.*; public class ReadExcel { public static void main(String[] args) throws FileNotFoundException, IOException { // Will contain cell name / value pair for input cells Map<String, String> inputCellsMap = new HashMap<String, String>(); // Will contain cell name for output cells List<String> outputCells = new ArrayList<String>(); // Open the Excel file FileInputStream file = new FileInputStream(new File(args[0])); // Get the current workbook HSSFWorkbook workbook = new HSSFWorkbook(file); // Get the input cells that need to be modified and // store their name and value in the inputCellsMap for (String element : args[1].split(";")) { inputCellsMap.put(element.split("=")[0], element.split("=")[1]); } // Get the output cells that will be accessed for resulting values for (String element : args[2].split(";")) { outputCells.add(element); } // Loop through the cells that need to be modified and // set the new value in the Excel document Iterator<Entry<String,String>> inputIterator = inputCellsMap.entrySet().iterator(); while (inputIterator.hasNext()) { Map.Entry<String,String> inputEntry = (Map.Entry<String,String>) inputIterator.next(); CellReference cellReferenceInput = new CellReference(inputEntry.getKey()); int cellReferenceInputRow = cellReferenceInput.getRow(); int cellReferenceInputColumn = cellReferenceInput.getCol(); // Get sheet name for each input cell HSSFSheet inputSheet = workbook.getSheet(inputEntry.getKey().split("!")[0]); Row rowInput = inputSheet.getRow(cellReferenceInputRow); if (rowInput == null) rowInput = inputSheet.createRow(cellReferenceInputRow); Cell cellInput = rowInput.getCell(cellReferenceInputColumn, Row.CREATE_NULL_AS_BLANK); cellInput.setCellValue(Integer.parseInt(inputEntry.getValue())); } // Apply all formulas after altering cell values workbook.getCreationHelper().createFormulaEvaluator().evaluateAll(); // Get the results from the output cells for (int i = 0; i < outputCells.size(); i++) { CellReference cellReferenceOutput = new CellReference(outputCells.get(i)); int cellReferenceOutputRow = cellReferenceOutput.getRow(); int cellReferenceOutputColumn = cellReferenceOutput.getCol(); // Get sheet name for each output cell HSSFSheet outputSheet = workbook.getSheet(outputCells.get(i).split("!")[0]); Row rowOutput = outputSheet.getRow(cellReferenceOutputRow); Cell cellOutput = rowOutput.getCell(cellReferenceOutputColumn, Row.CREATE_NULL_AS_BLANK); // Display results switch (cellOutput.getCellType()) { case Cell.CELL_TYPE_BOOLEAN: System.out.println(cellOutput.getBooleanCellValue()); break; case Cell.CELL_TYPE_NUMERIC: System.out.println(cellOutput.getNumericCellValue()); break; case Cell.CELL_TYPE_STRING: System.out.println(cellOutput.getStringCellValue()); break; case Cell.CELL_TYPE_BLANK: break; case Cell.CELL_TYPE_FORMULA: switch (cellOutput.getCachedFormulaResultType()) { case Cell.CELL_TYPE_STRING: System.out.println(cellOutput.getRichStringCellValue()); break; case Cell.CELL_TYPE_NUMERIC: HSSFCellStyle style = (HSSFCellStyle) cellOutput.getCellStyle(); if (style == null) { System.out.println(cellOutput.getNumericCellValue()); } else { DataFormatter formatter = new DataFormatter(); System.out.println(formatter. formatRawCellContents( cellOutput.getNumericCellValue(), style.getDataFormat(), style.getDataFormatString()) ); } break; case HSSFCell.CELL_TYPE_BOOLEAN: System.out.println(cellOutput.getBooleanCellValue()); break; case HSSFCell.CELL_TYPE_ERROR: System.out.println(ErrorEval.getText(cellOutput.getErrorCellValue())); break; } break; } } workbook.close(); } } 

 case Cell.CELL_TYPE_FORMULA: System.out.println(cellOutput.getNumericCellValue()); break; 

实际上应该是:

 case Cell.CELL_TYPE_FORMULA: System.out.println(cellOutput.getCellFormula()); break; 

之后你可以做:

 case Cell.CELL_TYPE_FORMULA: System.out.println(cellOutput.getCellFormula()); switch(cellOutput.getCachedFormulaResultType()) { case Cell.CELL_TYPE_NUMERIC: System.out.println(cellOutput.getNumericCellValue()); break; 

有关更多信息,请参阅文档

你的例外很清楚:

线程“main”中的exceptionjava.lang.IllegalStateException:无法从错误公式单元格获取数值。

你有一个公式单元格,评估一个错误。 因此,你不能获取它的数值,因为没有一个,只是错误值

因为你似乎在打印出单元格的值,所以简单的select就是使用DataFormatter将单元格格式化为一个string。 这需要关心细胞types,样式等所有的烦人的位。只需使用DataFormatter.formatCellValue(Cell) ,它会为你照顾它

如果没有,你需要检查单元格的types和评估types,例如

 if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) { switch(cell.getCachedFormulaResultType()) { case Cell.CELL_TYPE_ERROR: System.out.println(cell.getErrorCellValue()); break; case Cell.CELL_TYPE_NUMERIC: // Prints unstyled, use DataFormatter to style it System.out.println(cell.getNumericCellValue()); break; // TODO Remaining cell types