在 Excel (XLSX) 中聚焦并确认公式之前,不会对公式单元格进行评估
Formula cell does not get evaluated until formula is focussed and confirmed in Excel (XLSX)
所以我使用 Apache POI(最新稳定版本 5.0.0 中的 poi-ooxml)并打开一个 existing Excel (XSLX) 文件进行编辑 (它基本上是一个用附加数据填充的模板文件)。我添加了多个新数据行并再次导出 Excel。一切正常,只要我只添加常规内容单元格。
现在,我有一列要在其中添加公式单元格,我使用以下内容(针对此示例进行了简化,您可以放心,通常它 compiles/runs 并生成填充的 Excel 文件末尾)这样做的代码:
File excelFileToRead = new File(<some filename here>);
InputStream inp = new FileInputStream(excelFileToRead);
Workbook wb = WorkbookFactory.create(inp);
Sheet sheet = wb.getSheetAt(0);
Row dateRangeRow = sheet.getRow(0);
// fill first cell with some date
Cell cell = row.getCell(0);
if(cell == null) row.createCell(0)
Date someDate = new Date();
cell.setCellValue(someDate);
// add formula to second cell to display the week number
Cell formCell = row.getCell(1);
if(formCell == null) row.createCell(1);
cell.setCellFormula("WEEKNUM(A1)");
// evaluate all formula fields before saving
XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
//some routine to save as a file follows here, not exactly relevant here
总的来说,这很好用。创建第一个单元格并填充今天的日期,第二个单元格也创建为公式单元格。
现在问题来了:当我打开 Excel 传播sheet 时,我可以看到数据,但在公式单元格中我只看到“#WERT”(使用德语 Excel,我假设在英文版中它会显示类似“#VALUE”)的内容。
当我简单地点击 Excel 中的公式编辑器并再次移开焦点时,它会正确计算公式并且单元格显示正确的周数。
我之前在阅读 Excel 中的预先存在的公式时遇到了一些问题,当我将数据添加到 sheet 时它们没有更新,但这可以通过调用修复至 XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
出于某种原因,它不会影响我自定义创建的公式单元格。
我也试过在创建后单独评估新创建的公式单元格:
FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();
formulaEvaluator.evaluateFormulaCell(formCell);
这里也没有产生任何变化。
知道我的代码或方法有什么问题吗?
顺便说一句,我使用 Excel 版本 16.53(Excel 代表 Mac),但我真的希望它与确切的 Excel 版本无关:- )
注意:
我发现了一个旧线程(在 POI 5.0.0 发布之前)似乎讨论了同样的问题,但是使用较旧的 POI 版本并且如上所述,我遵循了调用 evaluateAllFormulaCells(...)在保存之前甚至在每个公式单元格创建之后调用 evaluateFormulaCell(cell):Apache POI formulas not evaluating
这是由于评估 WEEKNUM 函数时 apache poi
中的错误造成的。
如果 [return_type]
被省略,那么 ist 的计算结果总是 #VALUE
错误。但是即使你设置 [return_type]
然后它的评估并不总是正确的。
如果你这样做,你可以看到这个:
...
FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();
CellValue cellValue = formulaEvaluator.evaluate(formCell);
System.out.println(cellValue);
...
如果 A1
包含日期 9/27/2021
并且 B1
包含公式 =WEEKNUM(A1)
那么 apache poi
FormulaEvaluator
计算结果为 #VALUE
.如果 B1
包含公式 =WEEKNUM(A1,1)
,则 apache poi
FormulaEvaluator
将其计算为 39
,但 Excel
将其计算为 40
。
要解决此错误,可以强制 Excel
在打开文件时计算所有公式。这可以使用 wb.setForceFormulaRecalculation(true);
来完成。然后 Excel
计算公式,所以结果是正确的。
重现问题的完整示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
import java.util.GregorianCalendar;
class CreateExcelFormulaWEEKNUM {
public static void main(String[] args) throws Exception {
try (
//Workbook wb = WorkbookFactory.create(new FileInputStream("./ExcelIn.xls")); FileOutputStream fileout = new FileOutputStream("./ExcelOut.xls");
Workbook wb = WorkbookFactory.create(new FileInputStream("./ExcelIn.xlsx")); FileOutputStream fileout = new FileOutputStream("./ExcelOut.xlsx");
) {
Sheet sheet = wb.getSheetAt(0);
Row row = sheet.getRow(0); if (row == null) row = sheet.createRow(0);
Cell cell = row.getCell(0); if (cell == null) cell = row.createCell(0);
cell.setCellValue(new GregorianCalendar(2021, 8, 27));
CellReference cellReference = new CellReference(cell);
Cell formCell = row.getCell(1); if(formCell == null) formCell = row.createCell(1);
formCell.setCellFormula("WEEKNUM(" + cellReference.formatAsString() + ")"); // FormulaEvaluator evaluates to #VALUE because of [return_type] is not set
//formCell.setCellFormula("WEEKNUM(" + cellReference.formatAsString() + ", 1)"); // FormulaEvaluator evaluates to 39 which is wrong as Excel evaluates to 40
FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();
CellValue cellValue = formulaEvaluator.evaluate(formCell);
System.out.println(cellValue);
BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
wb.setForceFormulaRecalculation(true);
wb.write(fileout);
}
}
}
所以我使用 Apache POI(最新稳定版本 5.0.0 中的 poi-ooxml)并打开一个 existing Excel (XSLX) 文件进行编辑 (它基本上是一个用附加数据填充的模板文件)。我添加了多个新数据行并再次导出 Excel。一切正常,只要我只添加常规内容单元格。
现在,我有一列要在其中添加公式单元格,我使用以下内容(针对此示例进行了简化,您可以放心,通常它 compiles/runs 并生成填充的 Excel 文件末尾)这样做的代码:
File excelFileToRead = new File(<some filename here>);
InputStream inp = new FileInputStream(excelFileToRead);
Workbook wb = WorkbookFactory.create(inp);
Sheet sheet = wb.getSheetAt(0);
Row dateRangeRow = sheet.getRow(0);
// fill first cell with some date
Cell cell = row.getCell(0);
if(cell == null) row.createCell(0)
Date someDate = new Date();
cell.setCellValue(someDate);
// add formula to second cell to display the week number
Cell formCell = row.getCell(1);
if(formCell == null) row.createCell(1);
cell.setCellFormula("WEEKNUM(A1)");
// evaluate all formula fields before saving
XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
//some routine to save as a file follows here, not exactly relevant here
总的来说,这很好用。创建第一个单元格并填充今天的日期,第二个单元格也创建为公式单元格。
现在问题来了:当我打开 Excel 传播sheet 时,我可以看到数据,但在公式单元格中我只看到“#WERT”(使用德语 Excel,我假设在英文版中它会显示类似“#VALUE”)的内容。
当我简单地点击 Excel 中的公式编辑器并再次移开焦点时,它会正确计算公式并且单元格显示正确的周数。
我之前在阅读 Excel 中的预先存在的公式时遇到了一些问题,当我将数据添加到 sheet 时它们没有更新,但这可以通过调用修复至 XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
出于某种原因,它不会影响我自定义创建的公式单元格。
我也试过在创建后单独评估新创建的公式单元格:
FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();
formulaEvaluator.evaluateFormulaCell(formCell);
这里也没有产生任何变化。
知道我的代码或方法有什么问题吗?
顺便说一句,我使用 Excel 版本 16.53(Excel 代表 Mac),但我真的希望它与确切的 Excel 版本无关:- )
注意: 我发现了一个旧线程(在 POI 5.0.0 发布之前)似乎讨论了同样的问题,但是使用较旧的 POI 版本并且如上所述,我遵循了调用 evaluateAllFormulaCells(...)在保存之前甚至在每个公式单元格创建之后调用 evaluateFormulaCell(cell):Apache POI formulas not evaluating
这是由于评估 WEEKNUM 函数时 apache poi
中的错误造成的。
如果 [return_type]
被省略,那么 ist 的计算结果总是 #VALUE
错误。但是即使你设置 [return_type]
然后它的评估并不总是正确的。
如果你这样做,你可以看到这个:
...
FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();
CellValue cellValue = formulaEvaluator.evaluate(formCell);
System.out.println(cellValue);
...
如果 A1
包含日期 9/27/2021
并且 B1
包含公式 =WEEKNUM(A1)
那么 apache poi
FormulaEvaluator
计算结果为 #VALUE
.如果 B1
包含公式 =WEEKNUM(A1,1)
,则 apache poi
FormulaEvaluator
将其计算为 39
,但 Excel
将其计算为 40
。
要解决此错误,可以强制 Excel
在打开文件时计算所有公式。这可以使用 wb.setForceFormulaRecalculation(true);
来完成。然后 Excel
计算公式,所以结果是正确的。
重现问题的完整示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
import java.util.GregorianCalendar;
class CreateExcelFormulaWEEKNUM {
public static void main(String[] args) throws Exception {
try (
//Workbook wb = WorkbookFactory.create(new FileInputStream("./ExcelIn.xls")); FileOutputStream fileout = new FileOutputStream("./ExcelOut.xls");
Workbook wb = WorkbookFactory.create(new FileInputStream("./ExcelIn.xlsx")); FileOutputStream fileout = new FileOutputStream("./ExcelOut.xlsx");
) {
Sheet sheet = wb.getSheetAt(0);
Row row = sheet.getRow(0); if (row == null) row = sheet.createRow(0);
Cell cell = row.getCell(0); if (cell == null) cell = row.createCell(0);
cell.setCellValue(new GregorianCalendar(2021, 8, 27));
CellReference cellReference = new CellReference(cell);
Cell formCell = row.getCell(1); if(formCell == null) formCell = row.createCell(1);
formCell.setCellFormula("WEEKNUM(" + cellReference.formatAsString() + ")"); // FormulaEvaluator evaluates to #VALUE because of [return_type] is not set
//formCell.setCellFormula("WEEKNUM(" + cellReference.formatAsString() + ", 1)"); // FormulaEvaluator evaluates to 39 which is wrong as Excel evaluates to 40
FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();
CellValue cellValue = formulaEvaluator.evaluate(formCell);
System.out.println(cellValue);
BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
wb.setForceFormulaRecalculation(true);
wb.write(fileout);
}
}
}