今天測試反饋用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;
}
然後就大功告成了