2016-08-01 98 views
1

過去数日間、これは私を狂ってしまいました。Excelセル内の外部参照を使用するFormulaEvaluator.evaluateAll()は、Apache POIを使用してRuntimeExceptionを返します。

2つのExcelファイルを検討してください:ここでは a.xlsxb.xlsx

b.xlsxへの外部参照を含むa.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 
+1

私はapache-poiに慣れていませんが、エラー出力 "外部のブック名 'b.xlsx'を解決できませんでした。ブックブック環境が設定されていません。 –

+0

私はワークブック環境をセットアップしました。 – Abid357

+0

ええ、わかります。がんばろう。 –

答えて

0

あなたは、Apache POI 3.15ベータ3以降、または//2016年8月4日の後に/上のgitからビルドSVNからビルドナイトリービルドを使用する必要があります。 covered in the Apache POI changelogように、これはその後、その中に修正してビルド/リリースを使用して

を修正しましたXSSF特有のバグだった、XSSFFormulaEvaluatorevaluateAll()への呼び出しは、今HSSFがやったように、既にセットアップ任意の参照ワークブックを使用します。ずっと。

2

それはHSSF(* .XLS)で問題なく動作します。

しかし、apache poiは混乱しています。だから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(); 
     } 
    } 

} 
+0

HSSFとXSSFの違いはありません。あなたが問題を示す小さなjunitテストを書くことができ、それをPOI bugzillaにアップロードすることができれば、私は一度見ておきます! – Gagravarr

+0

@Gagravarr:私の説明と私のサンプルコードは、問題がどこにあるかを明確に示しています。 'evaluator1.evaluateAll();'で失敗します。 'evaluateAllFormulaCells(workbook1、evaluator1);でそれは動作します。 'a.xls'と' b.xls'を持つことは 'evaluateator1.evaluateAll();'と同様に働きます。 –

関連する問題