在Excel单元格中使用外部引用的FormulaEvaluator.evaluateAll()将使用Apache POI返回RuntimeException

在过去的几天里,这一直使我疯狂。

请考虑两个Excel文件: a.xlsx和b.xlsx

以下是应该评估a.xlsx中单元格的代码,包括对b.xlsx的外部引用。

import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.poi.ss.usermodel.FormulaEvaluator; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class Test { public static void main(String[] args) { try { FileInputStream file1 = new FileInputStream("C:\\Users\\Abid\\Desktop\\a.xlsx"); FileInputStream file2 = new FileInputStream("C:\\Users\\Abid\\Desktop\\b.xlsx"); XSSFWorkbook workbook1 = new XSSFWorkbook(file1); XSSFWorkbook workbook2 = new XSSFWorkbook(file2); FormulaEvaluator evaluator1 = workbook1.getCreationHelper().createFormulaEvaluator(); FormulaEvaluator evaluator2 = workbook2.getCreationHelper().createFormulaEvaluator(); Map<String, FormulaEvaluator> workbooks = new HashMap<String, FormulaEvaluator>(); workbooks.put("a.xlsx", evaluator1); workbooks.put("b.xlsx", evaluator2); evaluator1.setupReferencedWorkbooks(workbooks); evaluator1.evaluateAll(); file1.close(); file2.close(); workbook1.close(); workbook2.close(); } catch (IOException e) { e.printStackTrace(); } } } 

不幸的是,这是我执行后得到的结果:

  Exception in thread "main" java.lang.RuntimeException: Could not resolve external workbook name 'b.xlsx'. Workbook environment has not been set up. at org.apache.poi.ss.formula.OperationEvaluationContext.createExternSheetRefEvaluator(OperationEvaluationContext.java:113) at org.apache.poi.ss.formula.OperationEvaluationContext.createExternSheetRefEvaluator(OperationEvaluationContext.java:84) at org.apache.poi.ss.formula.OperationEvaluationContext.getRef3DEval(OperationEvaluationContext.java:313) at org.apache.poi.ss.formula.WorkbookEvaluator.getEvalForPtg(WorkbookEvaluator.java:634) at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:505) at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:263) at org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:205) at org.apache.poi.xssf.usermodel.BaseXSSFFormulaEvaluator.evaluateFormulaCellValue(BaseXSSFFormulaEvaluator.java:189) at org.apache.poi.xssf.usermodel.BaseXSSFFormulaEvaluator.evaluateFormulaCell(BaseXSSFFormulaEvaluator.java:117) at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateAllFormulaCells(HSSFFormulaEvaluator.java:346) at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateAllFormulaCells(HSSFFormulaEvaluator.java:337) at org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateAll(XSSFFormulaEvaluator.java:105) at Test.main(Test.java:28) Caused by: org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment$WorkbookNotFoundException: Could not resolve external workbook name 'b.xlsx'. Workbook environment has not been set up. at org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.getWorkbookEvaluator(CollaboratingWorkbooksEnvironment.java:195) at org.apache.poi.ss.formula.WorkbookEvaluator.getOtherWorkbookEvaluator(WorkbookEvaluator.java:156) at org.apache.poi.ss.formula.OperationEvaluationContext.createExternSheetRefEvaluator(OperationEvaluationContext.java:111) ... 12 more 

您需要使用Apache POI 3.15testing版3或更新版本,或者从2016年4月4日之后的git /之后的svn / build版本开始每晚构build/构build。 正如Apache POI更新日志中所述 ,这是一个后来修复的特定于XSSF的错误

如果使用构build/发行版以及修订版,则对XSSFFormulaEvaluator evaluateAll()调用现在将使用已经设置的任何引用的工作簿,就像HSSF一直XSSFFormulaEvaluator一样。

这将工作没有问题与HSSF (* .xls)。

但是apache poi是一团糟。 因此, XSSFFormulaEvaluator.evaluateAll()将简单地调用HSSFFormulaEvaluator.evaluateAllFormulaCells(_book); 。 但HSSFFormulaEvaluator.evaluateAllFormulaCells(Workbook wb)将创build一个新的 FormulaEvaluator ,它不涉及到环境中。

相反,它应该调用HSSFFormulaEvaluator.evaluateAllFormulaCells(工作簿wb,FormulaEvaluator评估者)并交出环境中涉及的FormulaEvaluator 。 但是这个方法是private

幸运的是,它并没有那么大和独立。 所以我们可以在我们的代码中使用这个方法:

 import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.poi.ss.usermodel.*; public class TestEvaluateExtRef { private static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) { for(int i=0; i<wb.getNumberOfSheets(); i++) { Sheet sheet = wb.getSheetAt(i); for(Row r : sheet) { for (Cell c : r) { if (c.getCellType() == Cell.CELL_TYPE_FORMULA) { evaluator.evaluateFormulaCell(c); } } } } } public static void main(String[] args) { try { Workbook workbook1 = WorkbookFactory.create(new FileInputStream("a.xlsx")); Workbook workbook2 = WorkbookFactory.create(new FileInputStream("b.xlsx")); FormulaEvaluator evaluator1 = workbook1.getCreationHelper().createFormulaEvaluator(); FormulaEvaluator evaluator2 = workbook2.getCreationHelper().createFormulaEvaluator(); Map<String, FormulaEvaluator> workbooks = new HashMap<String, FormulaEvaluator>(); workbooks.put("a.xlsx", evaluator1); workbooks.put("b.xlsx", evaluator2); workbook2.getSheetAt(0).getRow(0).getCell(0).setCellValue(new java.util.Random().nextDouble()); evaluator1.setupReferencedWorkbooks(workbooks); //evaluator1.evaluateAll(); evaluateAllFormulaCells(workbook1, evaluator1); System.out.println(workbook1.getSheetAt(0).getRow(0).getCell(0)); System.out.println(workbook1.getSheetAt(0).getRow(0).getCell(0).getNumericCellValue()); workbook1.close(); workbook2.close(); } catch (Exception e) { e.printStackTrace(); } } }