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

然後就大功告成了

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