繁体   English   中英

Apache POI如何在流模式下使用公式?

[英]How can Apache POI use formulas in streaming mode?

我正在使用Apache POI 3.17(当前)。 当我使用HSSFCell.setFormula()插入诸如“ A1 + 17”之类的公式时,它将起作用。 当我在流模式下执行相同操作时,使用SXSSFCell.setFormula()公式会在输入行中出现(以“ =”开头),但单元格中的显示结果始终为0。

我尝试使用单元格类型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();

尽管在输入行中正确显示了公式,但三个单元格显示为124/0/0。

任何提示表示赞赏。

它适用于Excel 2016,当我打开示例文件时,我在单元格中获得了正确的结果。 Excel的较旧版本可能对此处理方式稍有不同,请尝试通过以下两件事来强制对公式进行求值

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

希望这两种方法之一也能使它对您有用。

答案没有回答为什么只有在将SXSSFCell用作公式单元格的情况下,OpenOffice / Libreoffice才会出现此问题的问题。 当使用XSSFCell作为公式单元格时,它不会发生。

答案是,即使根本不评估公式, SXSSFCell 始终使用单元格值。 最糟糕的是,如果根本不对公式求值,它将使用值0(零)。 这是数学中值0的根本滥用。 值0明确并不意味着没有价值或有一个未知的值。 这意味着存在值0,仅此而已。 因此该值0 应该被用作没有评估式的缓存公式结果。 相反,在计算公式之前,不得使用任何值。 XSSFCell完全一样。

因此,真正正确的答案必须是apache poi应该更正其SXSSFCell代码。

解决方法:

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

 }

}

当然,我应该提到我使用LibreOffice。 现在,我发现LibreOffice并非故意从Excel创建的工作表中重新计算公式,而是将POI表视为Excel创建的。

参见https://ask.libreoffice.org/en/question/12165/calc-auto-recalc-does-not-work/

更改LibreOffice设置(工具–选项– LibreOffice Calc –公式–文件加载时重新计算)会有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM