2017-09-25 25 views
1

私はApache POI 3.17(現在)を使用しています。私はHSSFCell.setFormula()を使って "A1 + 17"のような数式を挿入すると動作します。ストリーミングモードでSXSSFCell.setFormula()を使用して同じ処理を行うと、入力行に式が表示されますが、セルの表示結果は常に0になります。Apache POIはどのようにストリーミングモードで式を使用できますか?

NUMERICとFORMULAを入力します。入力行に数式が正しく表示されているが

final SXSSFWorkbook wb = new SXSSFWorkbook(); 
final SXSSFSheet sheet = wb.createSheet("Test-S"); 
final SXSSFRow row = sheet.createRow(0); 

final SXSSFCell cell1 = row.createCell(0); 
cell1.setCellType(CellType.NUMERIC); 
cell1.setCellValue(124); 

final SXSSFCell formulaCell1 = row.createCell(1); 
formulaCell1.setCellType(CellType.FORMULA); 
formulaCell1.setCellFormula("A1 + 17"); 

final SXSSFCell formulaCell2 = row.createCell(2); 
formulaCell2.setCellType(CellType.NUMERIC); 
formulaCell2.setCellFormula("A1+18"); 

FileOutputStream os = new FileOutputStream("/tmp/test-s.xlsx"); 
wb.write(os); 
wb.close(); 
os.close(); 

3個の細胞は、124/0/0として表示:ここに私の最小限の作業ではない例です。

ご迷惑をおかけして申し訳ございません。

答えて

2

私はExcel 2016で動作します。サンプルファイルを開くと、セルに正しい結果が得られます。おそらく、エクセルの古いバージョンでは少し違っこれを処理するには、次の二つのこと

// evaluate all formulas and store cached results 
wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); 
// suggest to Excel to recalculate the formulas itself as well 
sheet.setForceFormulaRecalculation(true); 

それは同様にあなたのために働くようになります2人のうまくいけば1での式の評価を強制してみてください。

+0

どうもありがとう! evaluateAll()はそのトリックを行いました。しかし、私は両方の提案された声明を残すつもりです。 – Renardo

+0

追加の注意点:evaluateAll()は、行がすでにフラッシュされているという例外をスローすることがあります。この場合、evaluateFormulaCellEnum(cell)を使用できます。 – Renardo

1

もちろん、私はLibreOfficeを使用していると述べていました。私は今、LibreOfficeが意図的にExcelで作成されたシートから数式を再計算しないこと、そしてPOIシートをExcelで作成したものと見なしていることがわかりました。

https://ask.libreoffice.org/en/question/12165/calc-auto-recalc-does-not-work/を参照してください。

LibreOfficeの設定を変更する(ツール - オプション - LibreOffice Calc - 公式 - ファイル読み込み時の再計算)に役立ちます。

1

OpenOffice/Libreofficeでこの問題が発生する理由は、SXSSFCellが式セルとして使用されている場合にのみ発生します。数式セルとしてXSSFCellを使用する場合は発生しません。

答えはSXSSFCell常には、数式がまったく評価されない場合でもセル値を使用します。また、最悪の場合は、数式がまったく評価されない場合は値0(ゼロ)が使用されます。これは、数学の価値0の根本的な誤用です。値0は明示的にではありません。は、値が存在しないか、または値が不明であることを意味します。つまり、0という値があり、それ以外の値は存在しません。したがって、値0はではなく、評価されない式のキャッシュ式結果としてを使用する必要があります。代わりにの値は、数式が評価されるまで使用する必要があります。正確はXSSFCellと同じです。

したがって、実際に正しい答えは、apache poiSXSSFCellコードを修正する必要があります。この時まで

回避策:

import java.io.FileOutputStream; 

import org.apache.poi.xssf.streaming.*; 

import org.apache.poi.ss.usermodel.CellType; 

import java.lang.reflect.Field; 

import java.util.TreeMap; 

public class CreateExcelSXSSFFormula { 

public static void main(String[] args) throws Exception { 

    SXSSFWorkbook wb = new SXSSFWorkbook(); 

    SXSSFSheet sheet = wb.createSheet("Test-S"); 
    SXSSFRow row = sheet.createRow(0); 

    SXSSFCell cell = row.createCell(0); 
    cell.setCellValue(124); 

    SXSSFFormulaonlyCell formulacell = new SXSSFFormulaonlyCell(row, 1); 
    formulacell.setCellFormula("A1+17"); 

    cell = row.createCell(2); 
    cell.setCellFormula("A1+17"); 

    formulacell = new SXSSFFormulaonlyCell(row, 3); 
    formulacell.setCellFormula("A1+18"); 

    cell = row.createCell(4); 
    cell.setCellFormula("A1+18"); 

    wb.write(new FileOutputStream("test-s.xlsx")); 
    wb.close(); 
    wb.dispose(); 

} 

private static class SXSSFFormulaonlyCell extends SXSSFCell { 

    SXSSFFormulaonlyCell(SXSSFRow row, int cellidx) throws Exception { 
    super(row, CellType.BLANK); 
    Field _cells = SXSSFRow.class.getDeclaredField("_cells"); 
    _cells.setAccessible(true); 
    @SuppressWarnings("unchecked") //we know the problem and expect runtime error if it possibly occurs 
    TreeMap<Integer, SXSSFCell> cells = (TreeMap<Integer, SXSSFCell>)_cells.get(row); 
    cells.put(cellidx, this); 
    } 

    @Override 
    public CellType getCachedFormulaResultTypeEnum() { 
    return CellType.BLANK; 
    } 

} 

} 
+0

ありがとうございました@Axel Richter;とても面白いですね。はい、SXSSFRowには保護されたメソッドやメンバがありませんので、それを拡張する唯一の合理的な方法は反映です。私は 'SXXSFCell'を見る。'getCachedFormulaResultTypeEnum()'は推奨されていません。おそらく、POI開発者が現在そのトピックに取り組んでいないこと、またはその使用が推奨されていないことを意味します。 – Renardo

+0

@Renardo:私の提供する回避策は解決策ではなく、回避策です。解決策は、 'SXSSFCell'のコードを変更して、評価されていない式のキャッシュされた式の結果として値**を使用しないようにすることです。しかし、「apache poi」の変更管理も変です。今日の時点で、apidocは 'SXSSFCell.getCachedFormulaResultTypeEnum()'を非推奨とし、 'SXSSFCell.getCachedFormulaResultType()'は 'CellType'を返します。しかし、実際のバージョン3.17では、** 'getCachedFormulaResultTypeEnum()'を使用し、 'getCachedFormulaResultType()'は 'int'を返しています。 –

関連する問題