问题描述
我遇到了以下问题:我编写了一个将值写入 xlsx 文件的 Java 程序.此 xlsx 文件使用公式计算新值.现在我想从 xlsx 文件中获取这个计算值.问题是,我没有将计算出的值输入到我的 Java 程序中,因为没有保存更改.所以我尝试编辑 xlsx 文件中的 xl/workbook.
workbook.setForceFormulaRecalculation(true)
计算在不手动保存文件的情况下无法读取的值.或者我编辑 xl/workbook.
public void edit0){zos.write(buffer, 0, len);}//}zos.flush();zos.closeEntry();}File excel = new File("D:\\Excels\\SO_Berechnung_nosave.xlsx");FileInputStream fis = new FileInputStream(excel);XSSFWorkbook book = new XSSFWorkbook(fis);FileOutputStream fos = new FileOutputStream("D:\\Excels\\SO_Berechnung_nosave.xlsx");book.setForceFormulaRecalculation(true);book.write(fos);fis.close();fos.flush();fos.close();for(Enumeration e = zipFile.entries(); e.hasMoreElements();){System.out.println("???????????????????????????");ZipEntry entryIn = (ZipEntry) e.nextElement();if(entryIn.getName().equalsIgnoreCase("xl/workbook.";String rFirstLine = "<?";String replaceCalcId = "";//2147483647 152511if(s.contains(searchCalcId)){s = s.replaceAll(searchCalcId, replaceCalcId);System.out.println("calcId old:" + searchCalcId);System.out.println("calcId new:" + replaceCalcId);}//替换备用String searchAlternateContent = "";String replaceAlternateContent = "我已经尝试将除 xl/workbook.
更新:
根据接受的答案,我不再使用上面的代码.我补充说book.getCreationHelper().createFormulaEvaluator().evaluateAll();
在以下上下文中添加到我的代码中:
FileOutputStream fos = new FileOutputStream(path);book.setForceFormulaRecalculation(true);//XSSFFormulaEvaluator.evaluateAllFormulaCells((XSSFWorkbook) book);book.getCreationHelper().createFormulaEvaluator().evaluateAll();book.write(fos);fis.close();fos.flush();fos.close();
现在我得到了以下异常:
线程AWT-EventQueue-0"中的异常java.lang.RuntimeException: Invalid ValueEval type传递给转换:(类org.apache.poi.ss.formula.eval.MissingArgEval)在 org.apache.poi.ss.formula.functions.MultiOperandNumericFunction.collectValue(MultiOperandNumericFunction.java:219)在 org.apache.poi.ss.formula.functions.MultiOperandNumericFunction.collectValues(MultiOperandNumericFunction.java:179)在 org.apache.poi.ss.formula.functions.MultiOperandNumericFunction.getNumberArray(MultiOperandNumericFunction.java:128)在 org.apache.poi.ss.formula.functions.MultiOperandNumericFunction.evaluate(MultiOperandNumericFunction.java:90)在 org.apache.poi.ss.formula.OperationEvaluatorFactory.evaluate(OperationEvaluatorFactory.java:132)在 org.apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:540)在 org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:303)在 org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:245)在 org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateFormulaCellValue(XSSFFormulaEvaluator.java:268)在 org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateFormulaCell(XSSFFormulaEvaluator.java:155)在 org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateAllFormulaCells(HSSFFormulaEvaluator.java:335)在 org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateAllFormulaCells(HSSFFormulaEvaluator.java:326)在 org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateAll(XSSFFormulaEvaluator.java:256)在 XLSXEditor.searchWriter(XLSXEditor.java:218)在 Main.fillTable(Main.java:962)在 Main.btShowActionPerformed(Main.java:715)在 Main.access$900(Main.java:25)在 Main$11.actionPerformed(Main.java:402)在 javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)在 javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)在 javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)在 javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)在 javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)在 java.awt.Component.processMouseEvent(Component.java:6533)在 javax.swing.JComponent.processMouseEvent(JComponent.java:3324)在 java.awt.Component.processEvent(Component.java:6298)在 java.awt.Container.processEvent(Container.java:2236)在 java.awt.Component.dispatchEventImpl(Component.java:4889)在 java.awt.Container.dispatchEventImpl(Container.java:2294)在 java.awt.Component.dispatchEvent(Component.java:4711)在 java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)在 java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)在 java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)在 java.awt.Container.dispatchEventImpl(Container.java:2280)在 java.awt.Window.dispatchEventImpl(Window.java:2746)在 java.awt.Component.dispatchEvent(Component.java:4711)在 java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)在 java.awt.EventQueue.access$500(EventQueue.java:97)在 java.awt.EventQueue$3.run(EventQueue.java:709)在 java.awt.EventQueue$3.run(EventQueue.java:703)在 java.security.AccessController.doPrivileged(Native Method)在 java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)在 java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)在 java.awt.EventQueue$4.run(EventQueue.java:731)在 java.awt.EventQueue$4.run(EventQueue.java:729)在 java.security.AccessController.doPrivileged(Native Method)在 java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)在 java.awt.EventQueue.dispatchEvent(EventQueue.java:728)在 java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)在 java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)在 java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)在 java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
我检查了我在公式中使用的所有函数这里 并且它们都提供.. 是否有问题,由本地化或其他原因引起?
解决方案 到目前为止,您的假设是正确的.
"所以我尝试编辑 xlsx 文件中的 xl/workbook.
但现在你走错了路.
workbook.setForceFormulaRecalculation(true)
将公式的重新计算委托给 Excel
的 GUI.如果 Excel
的 GUI 下次打开文件,则重新计算完成.重新计算时,发生了变化.所以关于保存更改的问题是合法的.并且只有在保存更改后,即重新计算的公式结果,这些结果才会存储在文件中.然后,只有在从该文件新建 Workbook
后,才能使用 apache poi
读取结果.
但是委托重新计算只是一个选项>重新计算公式.另一种选择是使用 FormulaEvaluator 和这是 evaluateAll 方法示例.
...workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();...
此后,所有公式都将使用 apache poi
进行评估,新结果将可重新读取.
当然,这仅适用于 apache poi
的 FormulaEvaluator
支持的公式.有一些不受支持.那么你不能简单地执行 evaluateAll
而必须只评估包含支持公式的单元格.
在这种情况下,关于公式评估的整章可能会引起关注.
更新:
如前所述,到目前为止,并非所有公式都受支持.而且 apache poi
不像 Excel
那样宽容.
根据问题的更新部分的错误,有一个MissingArgEval 又名遗漏的参数",用在通常不应有此类遗漏参数的公式中.
例如,Excel
允许在表示 0
的公式中不提供任何参数作为参数.例如.=INDEX(A:A,MATCH("Text",Z:Z,))
而不是 =INDEX(A:A,MATCH("Text",Z:Z,0))
.但是 apache poi
FormulaEvaluator
不会容忍这个.
所以您现在需要调查导致错误的公式.因此,evaluateAll
对单元格进行循环以进行评估,如 中所述公式评估 - 重新计算工作簿中的所有公式":
FormulaEvaluator evaluator = book.getCreationHelper().createFormulaEvaluator();对于(工作表:书){for (Row r : sheet) {对于(单元格 c:r){if (c.getCellType() == Cell.CELL_TYPE_FORMULA) {System.out.println(c.getAddress() + ":" + c.getCellFormula());evaluator.evaluateFormulaCell(c);}}}}
调试 System.out.println
应该告诉你是哪个单元导致了问题.
I've got the following Problem: I wrote a Java programm that writes values into a xlsx file. This xlsx file calculates new values using Formulas. Now I want to get this calculated Values out of the xlsx file. The Problem is, that I don't get the calculated values into my Java programm, because changes aren't saved.So I tryed to edit the xl/workbook.
workbook.setForceFormulaRecalculation(true)
to calculate Values that i can't read without manually saving the file. Or I edit the xl/workbook.
public void edit
I allready tryed to copy all
Update:
According to the accepted answer, I don't use the code above anymore. And i addedbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
to my code in the following context:
FileOutputStream fos = new FileOutputStream(path);
book.setForceFormulaRecalculation(true);
//XSSFFormulaEvaluator.evaluateAllFormulaCells((XSSFWorkbook) book);
book.getCreationHelper().createFormulaEvaluator().evaluateAll();
book.write(fos);
fis.close();
fos.flush();
fos.close();
And now i get the followign Exception:
Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: Invalid ValueEval type passed for conversion: (class org.apache.poi.ss.formula.eval.MissingArgEval)
at org.apache.poi.ss.formula.functions.MultiOperandNumericFunction.collectValue(MultiOperandNumericFunction.java:219)
at org.apache.poi.ss.formula.functions.MultiOperandNumericFunction.collectValues(MultiOperandNumericFunction.java:179)
at org.apache.poi.ss.formula.functions.MultiOperandNumericFunction.getNumberArray(MultiOperandNumericFunction.java:128)
at org.apache.poi.ss.formula.functions.MultiOperandNumericFunction.evaluate(MultiOperandNumericFunction.java:90)
at org.apache.poi.ss.formula.OperationEvaluatorFactory.evaluate(OperationEvaluatorFactory.java:132)
at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:540)
at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:303)
at org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:245)
at org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateFormulaCellValue(XSSFFormulaEvaluator.java:268)
at org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateFormulaCell(XSSFFormulaEvaluator.java:155)
at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateAllFormulaCells(HSSFFormulaEvaluator.java:335)
at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateAllFormulaCells(HSSFFormulaEvaluator.java:326)
at org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateAll(XSSFFormulaEvaluator.java:256)
at XLSXEditor.searchWriter(XLSXEditor.java:218)
at Main.fillTable(Main.java:962)
at Main.btShowActionPerformed(Main.java:715)
at Main.access$900(Main.java:25)
at Main$11.actionPerformed(Main.java:402)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6533)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6298)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
at java.awt.Container.dispatchEventImpl(Container.java:2280)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
I checked all functions I use in my fomulas here and they are all offered.. Could there be a problem, caused by the localization or something?
Until now your assumptions are correct.
But now you are on the wrong way.
The workbook.setForceFormulaRecalculation(true)
delegates the recalculation of formulas to Excel
's GUI. The recalculation is done if Excel
's GUI is opening the file next time. When recalculated, changes were made. So the question about save the changes is legit. And only after saving the changes, which are the recalculated formula results, those results will be stored in the file. And then the results will only be readable using apache poi
after new creating a Workbook
from that file.
But delegating the recalculation is only one option for recalculating formulas. The other option is using a FormulaEvaluator and it's evaluateAll method for example.
...
workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
...
After that all formulas will be evaluated using apache poi
and the new results will be rereadable.
Of course that only works for formulas which are supported by apache poi
' s FormulaEvaluator
. There are some which are not supported. Then you cannot simply do evaluateAll
but must only evaluate the cells which contains supported formulas.
In that context the whole chapter about Formula Evaluation may be of interest.
Update:
As said already not all formulas are supported until now. And apache poi
is not as tolerant as Excel
will be.
According to the error in the Update part of the question, there is a MissingArgEval aka "a missed argument" used in a formula which normally should not have such missed arguments.
For example Excel
tolerates simply giving nothing as a parameter in a formula where 0
is meant. For ex. =INDEX(A:A,MATCH("Text",Z:Z,))
instead of =INDEX(A:A,MATCH("Text",Z:Z,0))
. But the apache poi
FormulaEvaluator
will not tolerate this.
So you now needs investigating which formula causes the error. So instead evaluateAll
do looping over the cells to evaluate as described in Formula Evaluation - "Re-calculating all formulas in a Workbook":
FormulaEvaluator evaluator = book.getCreationHelper().createFormulaEvaluator();
for (Sheet sheet : book) {
for (Row r : sheet) {
for (Cell c : r) {
if (c.getCellType() == Cell.CELL_TYPE_FORMULA) {
System.out.println(c.getAddress() + ":" + c.getCellFormula());
evaluator.evaluateFormulaCell(c);
}
}
}
}
There the debug System.out.println
should tell you which cell causes the problem.
这篇关于如何使用 Apache-POI 在 Excel 中计算公式并避免“保存更改"消息框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!