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

Java Excel单元格中带有外部引用的FormulaEvaluator.evaluateAll()使用Apache POI返回RuntimeException,java,excel,apache-poi,Java,Excel,Apache Poi,在过去的几天里,这让我发疯 请考虑两个Excel文件: 及 以下是用于计算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.x

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

请考虑两个Excel文件: 及

以下是用于计算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();
        }
    }

}

它在使用
HSSF
(*.xls)时不会出现问题

但是ApachePOI是一团糟。因此只需调用
hssformulaevaluator.evaluateAllFormulaCells(_book)。但是将创建一个新的
公式化评估器
,它不在环境中涉及

相反,它应该调用并移交
FormulaEvaluator
,该已包含在环境中。但是这个方法是私有的

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

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();
        }
    }

}
import java.io.FileInputStream;
导入java.io.IOException;
导入java.util.HashMap;
导入java.util.Map;
导入org.apache.poi.ss.usermodel.*;
公共类TestEvaluateExtRef{
专用静态void evaluateAllFormulaCells(工作簿wb,FormulaEvaluator evaluator){

对于(int i=0;i您需要使用Apache POI 3.15 beta 3或更高版本,或者在2016-08-04上/之后使用svn的夜间构建/构建/git的构建。因为,这是一个XSSF特定的bug,随后已被修复


使用带有修复程序的构建/发行版,在
XSSFFormulaEvaluator
上调用
evaluateAll()
现在将使用任何已设置的引用工作簿,就像HSSF一直以来所做的那样。

我不熟悉apache poi,但我在错误输出中看到了这一点无法解析外部工作簿名称“b.xlsx”。尚未设置工作簿环境。"我确实设置了工作簿环境。是的,我明白了。祝你好运。你使用的是什么版本的Apache POI?如果不是最新版本,升级时会发生什么?我使用的是最新的稳定版本Apache POI 3.14。在这方面HSSF和XSSF之间应该没有区别。如果你能够编写一个小的junit测试来显示问题,并且可以将其上传到POI bugzilla,我很乐意看一看!@Gagravarr:我的解释和我的示例代码非常清楚问题所在。使用
evaluator1.evaluator1();
失败。使用
evaluateAllFormulaCells(工作簿1,evaluator1)
它可以工作。拥有
a.xls
b.xls
它也可以与
evaluator1.evaluateAll()一起工作;
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();
        }
    }

}