简体   繁体   English

使用 Apache-POI 库获取单元格内容时,我得到“无法从文本单元格获取数值”和相反的结果。 我如何解决它?

[英]When getting cell content using Apache-POI Library, I get both “Cannot get a numeric value from a text cell” and the reverse of that. How do I fix it?

I realize the question is a little confusing, but I didn't know how else to word it.我意识到这个问题有点令人困惑,但我不知道该怎么说。 Anyway, here is the original code:无论如何,这是原始代码:

private void readFile(String excelFileName) throws FileNotFoundException, IOException {
    XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(excelFileName));
    if (workbook.getNumberOfSheets() > 1){
        System.out.println("Please make sure there is only one sheet in the excel workbook.");
    }
    XSSFSheet sheet = workbook.getSheetAt(0);
    int numOfPhysRows = sheet.getPhysicalNumberOfRows();
    XSSFRow row;
    XSSFCell num;
    for(int y = 1;y < numOfPhysRows;y++){    //start at the 2nd row since 1st should be category names
        row = sheet.getRow(y);
        poNum = row.getCell(1);
        item = new Item(Integer.parseInt(poNum.getStringCellValue());
        itemList.add(item);
        y++;
    }
}

private int poiConvertFromStringtoInt(XSSFCell cell){
    int x = Integer.parseInt(Double.toString(cell.getNumericCellValue()));
    return x;
}

I am getting the following error:我收到以下错误:

Exception in thread "main" java.lang.IllegalStateException: Cannot get a numeric value from a text cell
    at org.apache.poi.xssf.usermodel.XSSFCell.typeMismatch(XSSFCell.java:781)
    at org.apache.poi.xssf.usermodel.XSSFCell.getNumericCellValue(XSSFCell.java:199)

Even if I change it to get either a string using XSSFCell.getStringCellValue() or even XFFSCell.getRichTextValue , I get the reverse of the above error message (and I am making sure to ultimately make it an int using Integer.parseInt(XSSFCell.getStringCellValue() ).即使我将其更改为使用XSSFCell.getStringCellValue()或什XFFSCell.getRichTextValue获取字符串,我也会得到与上述错误消息相反的信息(并且我确保最终使用Integer.parseInt(XSSFCell.getStringCellValue() )。

The error then reads:然后错误显示:

Exception in thread "main" java.lang.IllegalStateException: Cannot get a text value from a numeric cell
    at org.apache.poi.xssf.usermodel.XSSFCell.typeMismatch(XSSFCell.java:781)
    at org.apache.poi.xssf.usermodel.XSSFCell.getNumericCellValue(XSSFCell.java:199)

I know for a fact that the excel spreadsheet column is in fact a string.我知道 excel 电子表格列实际上是一个字符串。 I can't change the excel sheet as it is uploaded else where always using the same format and formatting each column first takes up to much processing time.我无法更改 excel 工作表,因为它在其他地方上载时始终使用相同的格式并首先格式化每列会占用大量处理时间。

Any suggestions?有什么建议么?

[Solution] Here is the solution code I came up with from @Wivani's help: [解决方案] 这是我从@Wivani 的帮助中得出的解决方案代码:

private long poiGetCellValue(XSSFCell cell){
    long x;
    if(cell.getCellType() == 0)
        x = (long)cell.getNumericCellValue();
    else if(cell.getCellType() == 1)
        x = Long.parseLong(cell.getStringCellValue());
    else
        x = -1;
    return x;
}
Use This as reference

switch (cell.getCellType()) {
                case Cell.CELL_TYPE_STRING:
                    System.out.println(cell.getRichStringCellValue().getString());
                    break;
                case Cell.CELL_TYPE_NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell)) {
                        System.out.println(cell.getDateCellValue());
                    } else {
                        System.out.println(cell.getNumericCellValue());
                    }
                    break;
                case Cell.CELL_TYPE_BOOLEAN:
                    System.out.println(cell.getBooleanCellValue());
                    break;
                case Cell.CELL_TYPE_FORMULA:
                    System.out.println(cell.getCellFormula());
                    break;
                default:
                    System.out.println();
            }

You can get value as String using the format defined for this cell:您可以使用为此单元格定义的格式获取值作为字符串:

final DataFormatter df = new DataFormatter();
final XSSFCell cell = row.getCell(cellIndex);
String valueAsString = df.formatCellValue(cell);

Thanks to this answer .感谢这个答案

Just use cell.setCellType(1);只需使用 cell.setCellType(1); before reading cell value and get it as String always, after that you can use it in your own format(type).在读取单元格值并将其始终作为字符串获取之前,之后您可以以自己的格式(类型)使用它。

Ravi拉维

Use the below code to read any data type from xcels using poi.使用以下代码使用 poi 从 xcels 读取任何数据类型。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Iterator;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 *
 * @author nirmal
 */
public class ReadWriteExcel {

    public static void main(String ar[]) {
        ReadWriteExcel rw = new ReadWriteExcel();
        rw.readDataFromExcel();

    }
    Object[][] data = null;

    public File getFile() throws FileNotFoundException {
        File here = new File("test/com/javaant/ssg/tests/test/data.xlsx");
        return new File(here.getAbsolutePath());

    }

    public Object[][] readDataFromExcel() {
        final DataFormatter df = new DataFormatter();
        try {

            FileInputStream file = new FileInputStream(getFile());
            //Create Workbook instance holding reference to .xlsx file
            XSSFWorkbook workbook = new XSSFWorkbook(file);

            //Get first/desired sheet from the workbook
            XSSFSheet sheet = workbook.getSheetAt(0);

            //Iterate through each rows one by one
            Iterator<Row> rowIterator = sheet.iterator();

            int rownum = 0;
            int colnum = 0;
            Row r=rowIterator.next();

            int rowcount=sheet.getLastRowNum();
            int colcount=r.getPhysicalNumberOfCells();
            data = new Object[rowcount][colcount];
            while (rowIterator.hasNext()) {
                Row row = rowIterator.next();

                //For each row, iterate through all the columns
                Iterator<Cell> cellIterator = row.cellIterator();
                colnum = 0;
                while (cellIterator.hasNext()) {

                    Cell cell = cellIterator.next();
                    //Check the cell type and format accordingly
                    data[rownum][colnum] =  df.formatCellValue(cell);
                    System.out.print(df.formatCellValue(cell));
                    colnum++;
                    System.out.println("-");
                }
                rownum++;
                System.out.println("");
            }
            file.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return data;
    }
}

I got also this bug with POI version 3.12final.我在 POI 版本 3.12final 中也遇到了这个错误。
I think that the bug is registered there: https://bz.apache.org/bugzilla/show_bug.cgi?id=56702 and I put a comment there with my analysis.我认为该错误已在此处注册: https://bz.apache.org/bugzilla/show_bug.cgi?id=56702我在那里发表了我的分析评论。

Here is the workaround I used: The exception was risen by HSSFCell.getNumericCellValue which was called by DateUtil.isCellDateFormatted.这是我使用的解决方法:由 DateUtil.isCellDateFormatted 调用的 HSSFCell.getNumericCellValue 引发了异常。 DateUtil.isCellDateFormatted does 2 things: DateUtil.isCellDateFormatted 做了两件事:
1) check the value type of the cell by calling HSSFCell.getNumericCellValue and then DateUtil.isValidExcelDate(), which is almost pointless here I think. 1)通过调用 HSSFCell.getNumericCellValue 然后 DateUtil.isValidExcelDate() 检查单元格的值类型,我认为这几乎没有意义。
2) check if the format of the cell is a date format 2)检查单元格的格式是否为日期格式

I copied the code of topic 2) above in a new function 'myIsADateFormat' and used it instead of DateUtil.isCellDateFormatted (that is quite dirty to copy library code, but it works...):我在新的 function 'myIsADateFormat' 中复制了上面主题 2) 的代码,并使用它代替了 DateUtil.isCellDateFormatted (复制库代码很脏,但它可以工作......):

private boolean myIsADateFormat(Cell cell){
    CellStyle style = cell.getCellStyle();
    if(style == null) return false;
    int formatNo = style.getDataFormat();
    String formatString = style.getDataFormatString();
    boolean result = DateUtil.isADateFormat(formatNo, formatString);
    return result;
}

If you need to check the value type first, you can use this too:如果您需要先检查值类型,您也可以使用它:

CellValue cellValue = evaluator.evaluate(cell);
int cellValueType = cellValue.getCellType();
if(cellValueType == Cell.CELL_TYPE_NUMERIC){
    if(myIsADateFormat(cell){
        ....
    }
}

Documentation clearly says not to setCellType to 1 instead use the DataFormatter like how Thierry has explained:文档清楚地表明不要将 setCellType 设置为 1,而是像 Thierry 解释的那样使用 DataFormatter:

https://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/Cell.html#setCellType(int) https://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/Cell.html#setCellType(int)

Ravi's solution works: Just use cell.setCellType(1); Ravi 的解决方案有效:只需使用 cell.setCellType(1); before reading cell value and get it as String always, after that you can use it in your own format(type).在读取单元格值并将其始终作为字符串获取之前,之后您可以以自己的格式(类型)使用它。

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

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