最近由于工作需要,需要写一个工具,实现搜索功能,数据来源为excel表格。
目前主要实现方式为两种,一种是基于jxl组件,另一种是POI。两种方式的区别在于,jxl 只能读取2003版的excel,即后缀为xls的文件。当今常用的excel都是07版了,使用的为xlsx后缀文件。基于XML的压缩文件格式取代了其目前专有的默认文件格式 xls. 所以如果还用jxl,解析代码中存在 解压缩以及解析xml 的代码。下面会大概提一下这种方法,网上也有很多例子。 JXL已经不再维护更新了,POI 比较强大,可以支持07版本。缺点就是不太适合android,需要重新打包poi,同时还会出现android 65K limit 的问题。网上解决65k 方法很多,这里就不多讲了,此处近贴出读取的部分代码,写excel也很简单,就不贴了。
使用JXL读取excel
读取xls
上面代码基本仅可以读取xls,对于数据的处理可根据自己需求修改。
读取xlsx
读取xlsx,就需要对其进行解压,遍历XML文件来获取所需数据。
public static String readXLSX(String path) { String str = ""; String v = null; boolean flat = false; List<String> ls = new ArrayList<String>(); try { ZipFile xlsxFile = new ZipFile(new File(path)); ZipEntry sharedStringXML = xlsxFile .getEntry("xl/sharedStrings.xml"); InputStream inputStream = xlsxFile.getInputStream(sharedStringXML); XmlPullParser xmlParser = Xml.newPullParser(); xmlParser.setInput(inputStream, "utf-8"); int evtType = xmlParser.getEventType(); Log.e("=====>","==xmlParser====>"+xmlParser.toString()); while (evtType != XmlPullParser.END_DOCUMENT) { switch (evtType) { case XmlPullParser.START_TAG: String tag = xmlParser.getName(); if (tag.equalsIgnoreCase("t")) { ls.add(xmlParser.nextText()); Log.e("=====>","===xmlParser===>"+ls.toString()); } break; case XmlPullParser.END_TAG: break; default: break; } evtType = xmlParser.next(); } ZipEntry sheetXML = xlsxFile.getEntry("xl/worksheets/sheet1.xml"); InputStream inputStreamsheet = xlsxFile.getInputStream(sheetXML); XmlPullParser xmlParsersheet = Xml.newPullParser(); xmlParsersheet.setInput(inputStreamsheet, "utf-8"); int evtTypesheet = xmlParsersheet.getEventType(); while (evtTypesheet != XmlPullParser.END_DOCUMENT) { switch (evtTypesheet) { case XmlPullParser.START_TAG: String tag = xmlParsersheet.getName(); Log.e("=====>","===tag222===>"+tag); if (tag.equalsIgnoreCase("row")) { } else if (tag.equalsIgnoreCase("c")) { String t = xmlParsersheet.getAttributeValue(null, "t"); if (t != null) { flat = true; System.out.println(flat + "有"); } else { System.out.println(flat + "没有"); flat = false; } } else if (tag.equalsIgnoreCase("v")) { v = xmlParsersheet.nextText(); if (v != null) { if (flat) { //new Bean(ls.get(Integer.parseInt(v))) str += ls.get(Integer.parseInt(v)) + " "; } else { str += v + " "; } } } break; case XmlPullParser.END_TAG: if (xmlParsersheet.getName().equalsIgnoreCase("row") && v != null) { str += "\n"; } break; } evtTypesheet = xmlParsersheet.next(); } System.out.println(str); } catch (ZipException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (XmlPullParserException e) { e.printStackTrace(); } if (str == null) { str = "解析文件出现问题"; } return str; }
此处代码可以看出 主要是解压遍历
"xl/sharedStrings.xml" 可以按照行取出所有数据(每遍历一次 取出一个单元格内容数据,横向推)
"xl/worksheets/sheet1.xml" 取出行、列的位置,并用换行 空格来替换。 lz 试过可以正常读取数据,但是对数据再进行二次处理感觉比较繁琐,就没有使用这种方法。
使用POI 读取execl
首先尝试直接使用maven库来导入POI包
compile group: 'org.apache.poi', name: 'poi', version: '3.15' compile group: 'org.apache.poi', name: 'poi-ooxml-schemas', version: '3.9' compile group: 'org.apache.poi', name: 'poi-ooxml', version: '3.15'
编译冲突,主要原因是
所以android工程无法直接引用这些包,于是所有的线索指向了 andruhon ,andruhon 重新打包POI ,精简掉一些与excel无关的东西。解决了duplicate class 的问题。具体相关例子可参看https://github.com/andruhon/android5xlsx。
实现代码如下:
public void readExcelByPoi(String filepath) { try { String cellInfo = "1"; InputStream stream =null; stream = new FileInputStream(filepath);//"mnt/sdcard/test.xls" // InputStream stream = getResources().openRawResource(R.raw.test1); XSSFWorkbook workbook = null; try { workbook = new XSSFWorkbook(stream); } catch (IOException e) { e.printStackTrace(); } XSSFSheet sheet = workbook.getSheetAt(0); int rowsCount = sheet.getPhysicalNumberOfRows();// 获取行数 // Row row = sheet.getRow(0);// 获取第一行(约定第一行是标题行) // String[] titles = new String[rowsCount]; // for (int i = 0; i < titles.length; i++) { // titles[i] = getCellFormatValue(row.getCell(i));//获取第一行内容 // } FormulaEvaluator formulaEvaluator = workbook.getCreationHelper().createFormulaEvaluator(); getWritableDatabase().beginTransaction();// 手动开启事务提高效率 for (int r = 1; r < rowsCount; r++) { Log.e("=======>","=======>"+rowsCount); Row row = sheet.getRow(r); int cellsCount = row.getPhysicalNumberOfCells(); nameKey = getCellAsString(row,0, formulaEvaluator); type = getCellAsString(row,1, formulaEvaluator); tab = getCellAsString(row,2, formulaEvaluator); mode = getCellAsString(row,3, formulaEvaluator); initial = getCellAsString(row,8, formulaEvaluator); steps = getCellAsString(row,9, formulaEvaluator); insert(nameKey, type, tab, mode, initial, steps); // for (int c = 0; c < cellsCount; c++) { // String value = getCellAsString(row, c, formulaEvaluator); // cellInfo = "r:" + r + "; c:" + c + "; v:" + value; // Log.e("====>", "====>" + cellInfo); //// printlnToUser(cellInfo); // } } getWritableDatabase().setTransactionSuccessful(); getWritableDatabase().endTransaction(); } catch (FileNotFoundException e) { e.printStackTrace(); }finally { getWritableDatabase().close(); } }
protected String getCellAsString(Row row, int c, FormulaEvaluator formulaEvaluator) {
String value = "";
try {
org.apache.poi.ss.usermodel.Cell cell = row.getCell(c);
CellValue cellValue = formulaEvaluator.evaluate(cell);
switch (cellValue.getCellType()) {
case org.apache.poi.ss.usermodel.Cell.CELL_TYPE_BOOLEAN:
value = ""+cellValue.getBooleanValue();
break;
case org.apache.poi.ss.usermodel.Cell.CELL_TYPE_NUMERIC:
double numericValue = cellValue.getNumberValue();
if(HSSFDateUtil.isCellDateFormatted(cell)) {
double date = cellValue.getNumberValue();
SimpleDateFormat formatter =
new SimpleDateFormat("dd/MM/yy");
value = formatter.format(HSSFDateUtil.getJavaDate(date));
} else {
value = ""+numericValue;
}
break;
case org.apache.poi.ss.usermodel.Cell.CELL_TYPE_STRING:
value = ""+cellValue.getStringValue();
break;
default:
}
} catch (NullPointerException e) {
/* proper error handling should be here */
}
return value;
}`
此处根据自己项目业务 将数据插入了sqlite 中。
关于POI 如果读取excel 可以参考以下文章:
https://my.oschina.net/andy1989/blog/499605
关于两个jar 包, 由于方法超过65k 需要进行MultiDexApplication 配置,我的项目没有Application,所以只需要在清单文件加上android:name="android.support.multidex.MultiDexApplication"
依赖compile 'com.android.support:multidex:1.0.1'
即可。
精简版的 poi 包连接:http://download.csdn.net/detail/aa123456fdf/9755632
基本所有的解决方案都再上面了,希望有更好思路的同学,留言反馈下自己的情况,大家一起学习交流。