POI使用:用poi接口不区分xls/xlsx格式解析Excel文档(41种日期格式解析方法,5种公式结果类型解析方法,3种常用数值类型精度控制办法)
一、使用poi解析excel文档
1、打开excel文件
/** * 解析excel文档(支持xls、xlsx格式) * @param path - 文件路径 * @param formula - 是否获取公式结果 * @param sdf - 日期格式 * @return List - 结果表 * @throws Exception - 打开文件失败 */ public List<Map> parse(String path, boolean formula, SimpleDateFormat sdf) throws Exception { path = this.getClass().getResource("/").getPath() + path; File file = new File(path); List<Map>list=null; if (file.isFile()) { Workbook wb = createWorkbook(file); System.out.println("当前活动sheet" + wb.getActiveSheetIndex()); System.out.println("当前几个文档"+wb.getNumberOfSheets()); list=new ArrayList<Map>(); int max=wb.getNumberOfSheets(); for(int sheetNum=0;sheetNum<max;sheetNum++){ list.add(getSheet(wb, sheetNum, formula, sdf));//解析sheet表 } } else { throw new Exception("文件不存在"); } return list; }
2、解析sheet表
/** * 获取sheet表内容 * @param wb - 文档 * @param sheetNum - 打开那张sheet表 * @param formula - 是否获得公式结果 * @param sdf - 日期格式 * @return Map - 结果表 */ public Map<Integer, Map<Integer, String>> getSheet(Workbook wb, int sheetNum, boolean formula, SimpleDateFormat sdf) { String sheetName = wb.getSheetName(sheetNum); System.out.println("打开了sheet表:" + sheetName); Sheet sheet = wb.getSheet(sheetName); Map<Integer, Map<Integer, String>> map=getRowAndCell(sheet, formula, sdf);//解析所有单元格 return map; }
3、解析单元格内容
/** * 从sheet表中获取每行每列的值 * @param sheet - sheet表 * @param formula - 是否获取公式结果 * @param sdf - 日期格式 * @return Map - 结果表 */ public Map<Integer, Map<Integer, String>> getRowAndCell(Sheet sheet, boolean formula, SimpleDateFormat sdf) { Map<Integer,Map<Integer,String>>rowMap=null; int firstRowNum = sheet.getFirstRowNum(); int lastRowNum = sheet.getLastRowNum(); if(lastRowNum>0){ rowMap=new HashMap<Integer,Map<Integer,String>>(); // 遍历行 for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++ ) { Row row = sheet.getRow(rowNum); int firstCellNum = row.getFirstCellNum(); int lastCellNum = row.getLastCellNum(); Map<Integer,String> cellMap=new HashMap<Integer,String> (); // 遍历列 for (int cellNum = firstCellNum; cellNum < lastCellNum; cellNum++ ) { Cell cell = row.getCell(cellNum); int type = cell.getCellType(); String data=getValue(cell, formula, sdf);//根据单元格具体类型获得内容 System.out.println("第" + rowNum + "行,第" + cellNum + "列,类型是" + type +",内容是:"+data); cellMap.put(cellNum, data); } rowMap.put(rowNum, cellMap); } } return rowMap; }
4、判断单元格类型并获取内容
/** * 判断数值类型自动解析日期格式等其他特殊类型 * * @param data - 存放数据 * @param cell - 单元格 * @param sdf - 日期格式 * @return String - 结果 */ private String parseDate(Cell cell, SimpleDateFormat sdf) { System.out.println("是否是有效的日期格式:"+DateUtil.isCellDateFormatted(cell)); //poi的日期判断仅适用于欧美日期格式,对中文日期不支持,另外增加两个方法判断中文格式日期 if (DateUtil.isCellDateFormatted(cell)||isReserved(cell.getCellStyle().getDataFormat())||isDateFormat(cell.getCellStyle().getDataFormatString())) { return sdf.format(cell.getDateCellValue()); } System.out.println("格式:"+cell.getCellStyle().getDataFormatString()+",类型"+cell.getCellStyle().getDataFormat()); Double d=cell.getNumericCellValue(); if(cell.getCellStyle().getDataFormat()==0) { DecimalFormat dfs = new DecimalFormat("0"); return dfs.format(d); } return String.valueOf(d); }
/** * 获取单元格内容 * @param cell - 单元格 * @param sdf - 日期格式 * @param formula - 是否得出公式结果 * @return String - 单元格内容 */ private String getValue(Cell cell, boolean formula, SimpleDateFormat sdf) { String data = null; switch (cell.getCellType()) { case Cell.CELL_TYPE_NUMERIC: // 数字 data = parseDate(cell, sdf); break; case Cell.CELL_TYPE_STRING: // 字符串 data = cell.getStringCellValue(); break; case Cell.CELL_TYPE_BOOLEAN: // Boolean data = String.valueOf(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_FORMULA: // 公式 // 解析公式 data = parseFormula(cell, formula); break; case Cell.CELL_TYPE_BLANK: // 空格 System.out.println("遇到一个空格"); data = null; break; case Cell.CELL_TYPE_ERROR:// 错误 System.out.println("遇到一个错误"); data = null; break; default: data = null; } return data; }
二、poi的6种基本类型
Cell.CELL_TYPE_STRING: // 字符串
Cell.CELL_TYPE_BOOLEAN: // Boolean
Cell.CELL_TYPE_FORMULA: // 公式
Cell.CELL_TYPE_BLANK: // 空格
Cell.CELL_TYPE_ERROR:// 错误
三、41种日期格式解析方法
注意:看着好像有几个是重复的,但是它们的日期格式是不一样的(比如yyyy-m-d与yyyy-mm-dd同样都是显示:2015-12-13)
日期表(1-41):
1 2015-12-13
2 2015年12月
3 2015年12月15日
4 十二月十六日
5 二〇一五年十二月
6 二〇一五年十二月十八日
7 12月13日
8 2015-12-13 12:00 AM
9 2015-12-14 0:00
10 15-12-15
11 12-16
12 12-17-15
13 12-18-15
14 19-Dec
15 20-Dec-15
16 21-Dec-15
17 Dec-15
18 December-15
19 D
20 D-15
21 2015年12月26日
22 2015年12月
23 二〇一五年十二月二十七日
24 二〇一五年十二月
25 十二月二十九日
26 12月30日
27 星期四
28 五
29 2016-1-2
30 2016-1-3 12:00 AM
31 2016-1-4 0:00
32 16-1-5
33 1-6
34 1-7-16
35 01-08-16
36 9-Jan
37 10-Jan-16
38 Jan-16
39 January-16
40 J
41 J-16
2、日期对应的类型(0-40对应上面日期表1-41)
序号=类型
0=14,
1=27,
2=31,
3=176,
4=177,
5=178,
6=28,
7=179,
8=22,
9=180,
10=181,
11=30,
12=182,
13=16,
14=15,
15=183,
16=17,
17=184,
18=185,
19=186,
20=187,
21=188,
22=189,
23=190,
24=191,
25=192,
26=193,
27=194,
28=195,
29=196,
30=197,
31=198,
32=199,
33=200,
34=201,
35=202,
36=203,
37=204,
38=205,
39=206,
40=207
3、对应的日期格式(0-40,同上):
0=m/d/yy,
1=reserved-0x1b,
2=reserved-0x1f,
3=[DBNum1][$-804]m"月"d"日",
4=[DBNum1][$-804]yyyy"年"m"月",
5=[DBNum1][$-804]yyyy"年"m"月"d"日",
6=reserved-0x1c,
7=yyyy/m/d\ h:mm\ AM/PM,
8=m/d/yy h:mm,
9=yy/m/d,
10=m/d,
11=reserved-0x1e,
12=mm/dd/yy,
13=d-mmm,
14=d-mmm-yy,
15=dd/mmm/yy,
16=mmm-yy,
17=mmmm/yy,
18=mmmmm,
19=mmmmm/yy,
20=yyyy"年"m"月"d"日";@,
21=yyyy"年"m"月";@,
22=[DBNum1][$-804]yyyy"年"m"月"d"日";@,
23=[DBNum1][$-804]yyyy"年"m"月";@,
24=[DBNum1][$-804]m"月"d"日";@,
25=m"月"d"日";@,
26=[$-804]aaaa;@,
27=[$-804]aaa;@,
28=yyyy/m/d;@,
29=[$-409]yyyy/m/d\ h:mm\ AM/PM;@,
30=yyyy/m/d\ h:mm;@,
31=yy/m/d;@,
32=m/d;@,
33=m/d/yy;@,
34=mm/dd/yy;@,
35=[$-409]d/mmm;@,
36=[$-409]d/mmm/yy;@,
37=[$-409]mmm/yy;@,
38=[$-409]mmmm/yy;@,
39=[$-409]mmmmm;@,
40=[$-409]mmmmm/yy;@
根据上述的格式进行单独判断就可以正确解析所有日期格式。下面是我的实现方式,可能效率不高,如果有其它高效的方法可以提出来,欢迎一起交流
4、解析数值类型中的日期:
/** * 判断数值类型自动解析日期格式等其他特殊类型 * * @param data - 存放数据 * @param cell - 单元格 * @param sdf - 日期格式 * @return String - 结果 */ private String parseDate(Cell cell, SimpleDateFormat sdf) { System.out.println("是否是有效的日期格式:"+DateUtil.isCellDateFormatted(cell)); //poi的日期判断仅适用于欧美日期格式,对中文日期不支持,另外增加两个方法判断中文格式日期 if (DateUtil.isCellDateFormatted(cell)||isReserved(cell.getCellStyle().getDataFormat())||isDateFormat(cell.getCellStyle().getDataFormatString())) { return sdf.format(cell.getDateCellValue()); } System.out.println("格式:"+cell.getCellStyle().getDataFormatString()+",类型"+cell.getCellStyle().getDataFormat()); Double d=cell.getNumericCellValue(); if(cell.getCellStyle().getDataFormat()==0) { DecimalFormat dfs = new DecimalFormat("0"); return dfs.format(d); } return String.valueOf(d); }
<span style="font-size:18px;"> /** * 是否是日期格式保留字段 * @return boolean<ul><li>true - 是保留字段</li><li>false - 不是</li></ul> */ private boolean isReserved(short reserv) { if(reserv>=27&&reserv<=31) { return true; } return false; } /** * 判断是否是中文日期格式 * @param isNotDate * @return boolean<ul><li>true - 是日期格式</li><li>false - 不是</li></ul> */ private boolean isDateFormat(String isNotDate) { if(isNotDate.contains("年")||isNotDate.contains("月")||isNotDate.contains("日")) { return true; } else if(isNotDate.contains("aaa;")||isNotDate.contains("AM")||isNotDate.contains("PM")) { return true; } return false; }</span>
四、5种公式类型及结果解析方法
1、公式只有一种,结果分为5种
2、解析5种公式
<span style="font-size:18px;"> /** * 解析公式 * * @param data - 存放数据 * @param cell - 单元格 * @param formula - 是否计算公式结果 * @return String - 结果 */ private String parseFormula(Cell cell, boolean formula) { String data = null; if (formula) { switch (cell.getCachedFormulaResultType()) { case 0: if (0 == cell.getCellStyle().getDataFormat()) { DecimalFormat df = new DecimalFormat("0"); data = df.format(cell.getNumericCellValue()); } else { data = String.valueOf(cell.getNumericCellValue()); } break; case 1: data = String.valueOf(cell.getRichStringCellValue()); break; case 4: data = String.valueOf(cell.getBooleanCellValue()); break; case 5: data = String.valueOf(cell.getErrorCellValue()); break; default: data = cell.getCellFormula(); } } else { data = cell.getCellFormula(); } return data; }</span>
五、3种数值类型(货币,浮点、整数)精度控制(正确解析整数型数值)
本文来自博客园,作者:eguid,没有作者允许禁止转载,取得作者同意后转载需注明作者名和原文链接:https://www.cnblogs.com/eguid/p/6821605.html