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

时间:2016-08-01 19:21:17

标签: java excel apache-poi

在过去的几天里,这让我发疯了。

请考虑两个Excel文件: a.xlsxb.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

2 个答案:

答案 0 :(得分:2)

HSSF(* .xls)无问题。

但阿帕奇是一团糟。因此XSSFFormulaEvaluator.evaluateAll()只会致电HSSFFormulaEvaluator.evaluateAllFormulaCells(_book);。但HSSFFormulaEvaluator.evaluateAllFormulaCells(Workbook wb)会创建 FormulaEvaluator,但不会涉及环境。

相反,它应该调用HSSFFormulaEvaluator.evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator)并移交已经包含在环境中的 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();
        }
    }

}

答案 1 :(得分:0)

您需要在2016-08-04之后/之后使用Apache POI 3.15 beta 3或更新版本,或者从git / swn / build开始每晚构建/构建。作为covered in the Apache POI changelog,这是一个特定于XSSF的错误,随后已经修复

使用带有修补程序的构建/发布,evaluateAll()XSSFFormulaEvaluator的调用现在将使用已设置的任何引用的工作簿,就像HSSF一直这样做。