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

然后就大功告成了

  • 3
    点赞
  • 13
    收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从心归零

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值