一、使用poi解析excel文档
1、打开excel文件
/** * 解析excel文档(支持xls、xlsx格式) * @param path - 文件路径 * @param formula - 是否获取公式结果 * @param sdf - 日期格式 * @return List - 结果表 * @throws Exception - 打开文件失败 */ public List
2、解析sheet表
/** * 获取sheet表内容 * @param wb - 文档 * @param sheetNum - 打开那张sheet表 * @param formula - 是否获得公式结果 * @param sdf - 日期格式 * @return Map - 结果表 */ public Map> 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 > map=getRowAndCell(sheet, formula, sdf);//解析所有单元格 return map; }
3、解析单元格内容
/** * 从sheet表中获取每行每列的值 * @param sheet - sheet表 * @param formula - 是否获取公式结果 * @param sdf - 日期格式 * @return Map - 结果表 */ public Map> getRowAndCell(Sheet sheet, boolean formula, SimpleDateFormat sdf) { Map >rowMap=null; int firstRowNum = sheet.getFirstRowNum(); int lastRowNum = sheet.getLastRowNum(); if(lastRowNum>0){ rowMap=new HashMap >(); // 遍历行 for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++ ) { Row row = sheet.getRow(rowNum); int firstCellNum = row.getFirstCellNum(); int lastCellNum = row.getLastCellNum(); Map cellMap=new HashMap (); // 遍历列 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种基本类型
三、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); }
/** * 是否是日期格式保留字段 * @return boolean - true - 是保留字段
- false - 不是
*/ private boolean isReserved(short reserv) { if(reserv>=27&&reserv<=31) { return true; } return false; } /** * 判断是否是中文日期格式 * @param isNotDate * @return boolean - true - 是日期格式
- false - 不是
*/ 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; }
四、5种公式类型及结果解析方法
1、公式只有一种,结果分为5种
2、解析5种公式
/** * 解析公式 * * @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; }