Ошибка при попытке получить формулу из книги Excel с помощью Apache POI

Я использую Apache POI для изменения некоторых значений в документе Excel, а затем считываю результат из разных ячеек. Все шло хорошо, пока я не получил тестовый документ от клиента. Проверив его, я обнаружил, что у меня есть две проблемы:

1) Когда я пытаюсь получить значение из ячейки с формулой, но возвращает результат в формате валюты со знаком в качестве префикса, я получаю сообщение об ошибке.

2) Когда я пытаюсь получить значение из ячейки, которая ссылается на другую ячейку, которая является формулой (например: ячейка B20 на листе 3 имеет значение «= Лист 2! A20», где A20 на листе 2 - это СУММА () формула.), я получаю сообщение об ошибке.

Ошибка: Exception in thread "main" java.lang.IllegalStateException: Cannot get a numeric value from a error formula cell.

Имя документа, столбцы ввода (где значения изменяются) и столбцы вывода (где значения считываются) берутся из командной строки.

Вы можете найти мой код ниже:

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

person Cosmin    schedule 20.09.2015    source источник


Ответы (3)



Ваше исключение довольно ясно:

Исключение в потоке "main" java.lang.IllegalStateException: невозможно получить числовое значение из ячейки формулы ошибки.

У вас есть ячейка формулы, которая оценивается как ошибка. Поэтому вы не можете получить его числовое значение, так как его нет, только значение ошибки

Поскольку то, что вы, кажется, делаете, это распечатывает значение ячейки, простой вариант — просто использовать DataFormatter, чтобы отформатировать ячейку в строку. Это позаботится обо всех мелочах, связанных с типами ячеек, стилями и т. д. Просто используйте DataFormatter.formatCellValue(Cell), и он позаботится об этом за вас.

Если нет, вам нужно проверить как тип ячейки, так и оцениваемый тип, например

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
person Gagravarr    schedule 21.09.2015
comment
Я делаю это уже. Проверьте конец моего кода. Спасибо. - person Cosmin; 21.09.2015

я бы посоветовал сделать

evaluator.clearAllCachedResultValues()

перед любой операцией с оценщиком, если он не создан только что.

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
 */
person Gangnus    schedule 06.03.2020