简体   繁体   English

尝试从带有 Apache POI 的 Excel 工作簿中获取公式时出错

[英]Error while trying to get the formula from an Excel workbook with Apache POI

I'm using Apache POI to alter some values in an Excel document and then read the result from different cells.我正在使用 Apache POI 更改 Excel 文档中的某些值,然后从不同的单元格读取结果。 Everything went ok until I got a test document from the client.一切都很顺利,直到我从客户那里得到了测试文档。 After testing it I found out that I have two issues:经过测试,我发现我有两个问题:

1) When I try to get the value from a cell that has a formula but returns the result formatted as currency with the € sign as a prefix I get an error. 1) 当我尝试从具有公式的单元格中获取值但返回格式为货币的结果时,以 € 符号为前缀,出现错误。

2) When I try to get the value from a cell that references another cell that is a formula (eg.: cell B20 from Sheet 3 has the value of "=Sheet 2!A20" where A20 in Sheet 2 is a SUM() formula.), I get an error. 2)当我尝试从引用另一个作为公式的单元格的单元格中获取值时(例如:工作表 3 中的单元格 B20 的值为“=工作表 2!A20”,其中工作表 2 中的 A20 是 SUM()公式。),我得到一个错误。

The error is: Exception in thread "main" java.lang.IllegalStateException: Cannot get a numeric value from a error formula cell .错误是: Exception in thread "main" java.lang.IllegalStateException: Cannot get a numeric value from a error formula cell

The document name, input columns (where the values are altered) and output columns (from where the values are read) are taken from the command line.文档名称、输入列(更改值的位置)和输出列(读取值的位置)取自命令行。

You can find my code bellow:你可以在下面找到我的代码:

package poitest;

import java.util.List;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.usermodel.*;

public class ReadExcel {
    public static void main(String[] args) throws FileNotFoundException, IOException {
        // Will contain cell name / value pair for input cells          
        Map<String, String> inputCellsMap = new HashMap<String, String>();

        // Will contain cell name for output cells
        List<String> outputCells = new ArrayList<String>();

        // Open the Excel file
        FileInputStream file = new FileInputStream(new File(args[0]));

        // Get the current workbook
        HSSFWorkbook workbook = new HSSFWorkbook(file);         

        // Get the input cells that need to be modified and
        // store their name and value in the inputCellsMap
        for (String element : args[1].split(";")) {
            inputCellsMap.put(element.split("=")[0], element.split("=")[1]);
        }

        // Get the output cells that will be accessed for resulting values
        for (String element : args[2].split(";")) {
            outputCells.add(element);           
        }

        // Loop through the cells that need to be modified and 
        // set the new value in the Excel document
        Iterator<Entry<String,String>> inputIterator = inputCellsMap.entrySet().iterator();
        while (inputIterator.hasNext()) {
            Map.Entry<String,String> inputEntry = (Map.Entry<String,String>) inputIterator.next();

            CellReference cellReferenceInput = new CellReference(inputEntry.getKey());
            int cellReferenceInputRow = cellReferenceInput.getRow();
            int cellReferenceInputColumn = cellReferenceInput.getCol();

            // Get sheet name for each input cell
            HSSFSheet inputSheet = workbook.getSheet(inputEntry.getKey().split("!")[0]);

            Row rowInput = inputSheet.getRow(cellReferenceInputRow);
            if (rowInput == null)
                rowInput = inputSheet.createRow(cellReferenceInputRow);
            Cell cellInput = rowInput.getCell(cellReferenceInputColumn, Row.CREATE_NULL_AS_BLANK);              
            cellInput.setCellValue(Integer.parseInt(inputEntry.getValue()));        
        }

        // Apply all formulas after altering cell values        
        workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();        

        // Get the results from the output cells
        for (int i = 0; i < outputCells.size(); i++) {
            CellReference cellReferenceOutput = new CellReference(outputCells.get(i));
            int cellReferenceOutputRow = cellReferenceOutput.getRow();
            int cellReferenceOutputColumn = cellReferenceOutput.getCol();

            // Get sheet name for each output cell
            HSSFSheet outputSheet = workbook.getSheet(outputCells.get(i).split("!")[0]);

            Row rowOutput = outputSheet.getRow(cellReferenceOutputRow);
            Cell cellOutput = rowOutput.getCell(cellReferenceOutputColumn, Row.CREATE_NULL_AS_BLANK);

            // Display results
            switch (cellOutput.getCellType()) {
                case Cell.CELL_TYPE_BOOLEAN:
                    System.out.println(cellOutput.getBooleanCellValue());
                    break;
                case Cell.CELL_TYPE_NUMERIC:
                    System.out.println(cellOutput.getNumericCellValue());
                    break;
                case Cell.CELL_TYPE_STRING:
                    System.out.println(cellOutput.getStringCellValue());
                    break;
                case Cell.CELL_TYPE_BLANK:
                    break;              
                case Cell.CELL_TYPE_FORMULA:                            
                    switch (cellOutput.getCachedFormulaResultType()) {
                        case Cell.CELL_TYPE_STRING:
                            System.out.println(cellOutput.getRichStringCellValue());                            
                            break;
                        case Cell.CELL_TYPE_NUMERIC:
                            HSSFCellStyle style = (HSSFCellStyle) cellOutput.getCellStyle();
                            if (style == null) {
                                System.out.println(cellOutput.getNumericCellValue());
                            } else {
                                DataFormatter formatter = new DataFormatter();
                                System.out.println(formatter.
                                        formatRawCellContents(
                                                cellOutput.getNumericCellValue(), 
                                                style.getDataFormat(),
                                                style.getDataFormatString())
                                        );
                            }
                            break;
                        case HSSFCell.CELL_TYPE_BOOLEAN:
                            System.out.println(cellOutput.getBooleanCellValue());
                            break;
                        case HSSFCell.CELL_TYPE_ERROR:
                            System.out.println(ErrorEval.getText(cellOutput.getErrorCellValue()));                          
                            break;
                    }

                    break;
            }                           
        }           

        workbook.close();       
    }
}
case Cell.CELL_TYPE_FORMULA:                    
    System.out.println(cellOutput.getNumericCellValue());
    break;

should actually be:实际上应该是:

case Cell.CELL_TYPE_FORMULA:                    
        System.out.println(cellOutput.getCellFormula());
        break;

After that you can do:之后你可以这样做:

case Cell.CELL_TYPE_FORMULA:                    
    System.out.println(cellOutput.getCellFormula());
    switch(cellOutput.getCachedFormulaResultType()) {
        case Cell.CELL_TYPE_NUMERIC:
        System.out.println(cellOutput.getNumericCellValue());
        break;

See the docs for more 查看文档了解更多

Your exception is pretty clear:你的例外很明显:

Exception in thread "main" java.lang.IllegalStateException: Cannot get a numeric value from a error formula cell.线程“main”中的异常 java.lang.IllegalStateException:无法从错误公式单元格中获取数值。

You have a formula cell which evaluated to an error.您有一个计算为错误的公式单元格。 Therefore, you can't fetch the numeric value of it, as there isn't one, just the error value因此,您无法获取它的数值,因为没有,只有错误值

Since what you seem to be doing is printing out the cell's value, the easy option is just to use DataFormatter to get the Cell formatted into a String.由于您似乎正在做的是打印出单元格的值,因此简单的选择就是使用DataFormatter将单元格格式化为字符串。 That takes care of all the fiddly bits around cell types, styles etc. Just use DataFormatter.formatCellValue(Cell) and it'll take care of it for you这会处理有关单元格类型、样式等的所有繁琐位。只需使用DataFormatter.formatCellValue(Cell)它将为您处理

If not, you need to check both the cell's type, and the evaluated type, eg如果没有,您需要检查单元格的类型和评估的类型,例如

if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
   switch(cell.getCachedFormulaResultType()) {
     case Cell.CELL_TYPE_ERROR:
        System.out.println(cell.getErrorCellValue());
        break;
     case Cell.CELL_TYPE_NUMERIC:
        // Prints unstyled, use DataFormatter to style it
        System.out.println(cell.getNumericCellValue());
        break;
     // TODO Remaining cell types

I would advice to do我会建议做

evaluator.clearAllCachedResultValues()

before any operation with evaluator if not created just now.如果不是刚刚创建,则在使用评估器进行任何操作之前。

Javadoc: Javadoc:

/**
 * Should be called whenever there are changes to input cells in the evaluated workbook.
 * Failure to call this method after changing cell values will cause incorrect behaviour
 * of the evaluate~ methods of this class
 */

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

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