excel 模板 POI JAVA 中的公式重新计算
Formula recalculation in excel template POI JAVA
我有一个 Excel 模板文件,在某些单元格中包含公式,我打开它并使用 POI 填充值。问题是公式不会自动重新计算。但是,如果我打开此文件并单击具有值的单元格,它会重新计算该单元格。
我在 documentation 中找到了两种解决此问题的方法,但都没有帮助我。
重点是Excel会缓存之前计算的结果,需要触发重新计算才能更新。
使用 POI 的 FormulaEvaluator 重新评估公式
workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
将重新计算委托给 Excel。打开工作簿时,应用程序将执行完整的重新计算
workbook.setForceFormulaRecalculation(true);
我的代码:
public static String fillBook(String filename, String outFilename, int sheetNumber, String[] params){
String result = "";
try {
File file = new File(filename);
Workbook workbook = null;
workbook = WorkbookFactory.create(file);
Sheet sheet = workbook.getSheetAt(sheetNumber);
for (String param: params)
{
String[] paramArray = param.split("\u0001");
String address = paramArray[0];
String value;
if (paramArray.length > 1)
{
value = paramArray[1];
} else {
value = "";
}
CellReference cellReference = new CellReference(address);
Row row = sheet.getRow(cellReference.getRow());
if (row == null) {
row = sheet.createRow(cellReference.getRow());
}
Cell cell = row.getCell(cellReference.getCol(), Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellValue(value);
}
//workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
workbook.setForceFormulaRecalculation(true);
FileOutputStream out = new FileOutputStream(outFilename);
workbook.write(out);
out.close();
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
result = e.toString() + " " + exceptionAsString;
}
return result;
}
您不应在 Excel 中将所有单元格值设置为字符串值。当引用的单元格包含字符串值时,需要数值或日期值的公式将不起作用。
从您提供的代码开始,您设置的所有新值都是字符串值。因此,如果 String[] paramArray
包含“123”,例如,您将字符串“123”而不是数字 123 设置为单元格值。但是例如公式 SUM
不能对字符串求和。它仅对数值求和。因此,只有当您将其中包含“123”的单元格更改为 123 时,它才会起作用。所以将数值设置为数值。 Cell
中有一些方法可以做到这一点。 void setCellValue(double value) 例如。
日期值也是如此。这些还需要设置为单元格中的日期值,而不是简单地设置为字符串。
所以您需要一个与 String[] params
不同的对象来传递单元格值。该对象也必须能够存储数值。例如 List<Object>
或 List<POJO>
,其中 POJO
是任何一种存储信息的普通旧 Java 对象。然后使用 Cell 的不同 setCellValue
方法来设置字符串单元格值或数字单元格值或日期单元格值。
否则,在将 Cell
设置为 Cell
之前,您需要根据从 String[] params
获得的字符串创建一个数值 (double
)。日期值相同 - 在将 Cell
设置为 Cell
之前,根据从 String[] params
获得的字符串创建一个日期值(Calendar
或 LocalDate
或 LocalDateTime
)。但在我看来,这是更容易出错的方法。
我有一个 Excel 模板文件,在某些单元格中包含公式,我打开它并使用 POI 填充值。问题是公式不会自动重新计算。但是,如果我打开此文件并单击具有值的单元格,它会重新计算该单元格。
我在 documentation 中找到了两种解决此问题的方法,但都没有帮助我。
重点是Excel会缓存之前计算的结果,需要触发重新计算才能更新。
使用 POI 的 FormulaEvaluator 重新评估公式
workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
将重新计算委托给 Excel。打开工作簿时,应用程序将执行完整的重新计算
workbook.setForceFormulaRecalculation(true);
我的代码:
public static String fillBook(String filename, String outFilename, int sheetNumber, String[] params){
String result = "";
try {
File file = new File(filename);
Workbook workbook = null;
workbook = WorkbookFactory.create(file);
Sheet sheet = workbook.getSheetAt(sheetNumber);
for (String param: params)
{
String[] paramArray = param.split("\u0001");
String address = paramArray[0];
String value;
if (paramArray.length > 1)
{
value = paramArray[1];
} else {
value = "";
}
CellReference cellReference = new CellReference(address);
Row row = sheet.getRow(cellReference.getRow());
if (row == null) {
row = sheet.createRow(cellReference.getRow());
}
Cell cell = row.getCell(cellReference.getCol(), Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellValue(value);
}
//workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
workbook.setForceFormulaRecalculation(true);
FileOutputStream out = new FileOutputStream(outFilename);
workbook.write(out);
out.close();
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
result = e.toString() + " " + exceptionAsString;
}
return result;
}
您不应在 Excel 中将所有单元格值设置为字符串值。当引用的单元格包含字符串值时,需要数值或日期值的公式将不起作用。
从您提供的代码开始,您设置的所有新值都是字符串值。因此,如果 String[] paramArray
包含“123”,例如,您将字符串“123”而不是数字 123 设置为单元格值。但是例如公式 SUM
不能对字符串求和。它仅对数值求和。因此,只有当您将其中包含“123”的单元格更改为 123 时,它才会起作用。所以将数值设置为数值。 Cell
中有一些方法可以做到这一点。 void setCellValue(double value) 例如。
日期值也是如此。这些还需要设置为单元格中的日期值,而不是简单地设置为字符串。
所以您需要一个与 String[] params
不同的对象来传递单元格值。该对象也必须能够存储数值。例如 List<Object>
或 List<POJO>
,其中 POJO
是任何一种存储信息的普通旧 Java 对象。然后使用 Cell 的不同 setCellValue
方法来设置字符串单元格值或数字单元格值或日期单元格值。
否则,在将 Cell
设置为 Cell
之前,您需要根据从 String[] params
获得的字符串创建一个数值 (double
)。日期值相同 - 在将 Cell
设置为 Cell
之前,根据从 String[] params
获得的字符串创建一个日期值(Calendar
或 LocalDate
或 LocalDateTime
)。但在我看来,这是更容易出错的方法。