poi导入excel数字出现精度问题

今天测试反馈用excel导入数据时出现精度问题,比如excel里面的4.6变成了4.59999999999999996,4.4变成了4.4000000000000001等。

我原先的代码是这样的

public static Object getCellFormatValue(Cell cell) throws ParseException{
        Object cellValue = null;
        if(cell!=null){
            //判断cell类型
            switch(cell.getCellType()){
            case Cell.CELL_TYPE_NUMERIC:{
            	//判断cell是否为日期格式
                if(DateUtil.isCellDateFormatted(cell)){
                    //转换为日期格式YYYY-mm-dd
                	Date date = cell.getDateCellValue();
                	SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                	cellValue = sdf.format(date);
                }else{
                	cell.setCellType(Cell.CELL_TYPE_STRING);
                    cellValue = cell.getRichStringCellValue().getString();
                    //数字
                    //cellValue = String.valueOf(cell.getNumericCellValue());
                }
                break;
            }
            case Cell.CELL_TYPE_FORMULA:{
                cellValue = String.valueOf(cell.getNumericCellValue());
                break;
            }
            case Cell.CELL_TYPE_STRING:{
            	cellValue = cell.getRichStringCellValue().getString();
                break;
            }
            default:
                cellValue = "";
            }
        }else{
            cellValue = "";
        }
        return cellValue;
    }

就是在类型是CELL_TYPE_NUMERIC时,如果不是日期类型,则强制转化为字符串类型,debug后发现就是在这一步时发生精度问题,有点不理解背后的原理,明明直接返回对应的字符串就行了。

尝试过后发现用cell.getNumericCellValue()可以返回正确的值4.6。但是这又会带来一个问题,那就是poi会把数字都变成double型,比如4会变成4.0,导入就会报错了,这时候我想要不先用cell.getStringCellValue()返回字符串判断是否有小数点,如果有小数点那么再用cell.getNumericCellValue()返回double类型

public static Object getCellFormatValue(Cell cell) throws ParseException{
        Object cellValue = null;
        if(cell!=null){
            //判断cell类型
            switch(cell.getCellType()){
            case Cell.CELL_TYPE_NUMERIC:{
            	//判断cell是否为日期格式
                if(DateUtil.isCellDateFormatted(cell)){
                    //转换为日期格式YYYY-mm-dd
                	Date date = cell.getDateCellValue();
                	SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                	cellValue = sdf.format(date);
                }else{
                	cell.setCellType(Cell.CELL_TYPE_STRING);
                    cellValue = cell.getStringCellValue();
                    if(((String)cellValue).indexOf(".") > -1){
                         cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                         cellValue = String.valueOf(cell.getNumericCellValue());
                    }
                }
                break;
            }
            case Cell.CELL_TYPE_FORMULA:{
                cellValue = String.valueOf(cell.getNumericCellValue());
                break;
            }
            case Cell.CELL_TYPE_STRING:{
            	cellValue = cell.getRichStringCellValue().getString();
                break;
            }
            default:
                cellValue = "";
            }
        }else{
            cellValue = "";
        }
        return cellValue;
    }

但是这个用法是不行的,在调用了cell的get方法后,cell的值就会改变,非常奇怪,无法理解,在逻辑上也不合理,get方法不应该改变对象内部的属性。

比如原值是4.6,调用了getStringCellValue后再调用getNumericCellValue就变成了19.0.原值是4.4,则会变成21.0,也不知道具体的逻辑。

总之cell的get方法只能调用一次。正在我一筹莫展的时候,我发现在debug时移到cell上面会直接显示数字4.6,那是不是意味着cell的toString方法可以直接显示单元格的内容。我尝试了一下,发现cell.toString方法在cellType为CELL_TYPE_NUMERIC时,就相当于getNumericCellValue方法,也会将数字都转化为double类型。但是调用toString方法不会改变cell的值。

public static String getCellFormatValue(Cell cell) throws ParseException{
        String cellValue = null;
        if(cell!=null){
            //判断cell类型
            switch(cell.getCellType()){
            case Cell.CELL_TYPE_NUMERIC:{
            	//判断cell是否为日期格式
                if(DateUtil.isCellDateFormatted(cell)){
                    //转换为日期格式YYYY-mm-dd
                	Date date = cell.getDateCellValue();
                	SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                	cellValue = sdf.format(date);
                }else{
                	String cellstr = cell.toString();
                	cell.setCellType(Cell.CELL_TYPE_STRING);
                	cellValue = cell.getStringCellValue();
                	if(cellValue.indexOf(".") > -1) {
                		cellValue = cellstr;
                	}
                }
                break;
            }
            case Cell.CELL_TYPE_FORMULA:{
                cellValue = String.valueOf(cell.getNumericCellValue());
                break;
            }
            case Cell.CELL_TYPE_STRING:{
            	cellValue = cell.getStringCellValue();
                break;
            }
            default:
                cellValue = "";
            }
        }else{
            cellValue = "";
        }
        return cellValue;
    }

然后就大功告成了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章