android 读取excel POI JXL

最近由于工作需要,需要写一个工具,实现搜索功能,数据来源为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'

Paste_Image.png

编译冲突,主要原因是

Paste_Image.png
所以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.youkuaiyun.com/detail/aa123456fdf/9755632

目前遗留问题:
Android 开发接触没几年,水平还很低,上述代码存在两个问题 希望大神可以相互交流,给出指正。
1.workbook = new XSSFWorkbook(stream); 处理数据很慢 我的表格的内容大概三千多行,需要五秒。
2. sqlite 插入数据 insert 这个用的感觉很蠢, 不会批量插入,现在就是一条一条插最后提交一个事务,速度也还行。 数据流的关闭上述代码也没处理
基本所有的解决方案都再上面了,希望有更好思路的同学,留言反馈下自己的情况,大家一起学习交流。

android 使用poi读取高版本excel, 解决以下这两个错误 java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/xml/stream/XMLEventFactory; at org.apache.poi.openxml4j.opc.internal.marshallers.PackagePropertiesMarshaller.(PackagePropertiesMarshaller.java:41) at org.apache.poi.openxml4j.opc.OPCPackage.init(OPCPackage.java:161) at org.apache.poi.openxml4j.opc.OPCPackage.(OPCPackage.java:141) at org.apache.poi.openxml4j.opc.ZipPackage.(ZipPackage.java:97) at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:324) at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:184) at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:149) javax.xml.stream.FactoryConfigurationError: Provider com.sun.xml.internal.stream.events.XMLEventFactoryImpl not found at javax.xml.stream.FactoryFinder.newInstance(Unknown Source) at javax.xml.stream.FactoryFinder.newInstance(Unknown Source) at javax.xml.stream.FactoryFinder.find(Unknown Source) at javax.xml.stream.FactoryFinder.find(Unknown Source) at javax.xml.stream.XMLEventFactory.newInstance(Unknown Source) at org.apache.poi.openxml4j.opc.internal.marshallers.PackagePropertiesMarshaller.(PackagePropertiesMarshaller.java:41) at org.apache.poi.openxml4j.opc.OPCPackage.init(OPCPackage.java:161) at org.apache.poi.openxml4j.opc.OPCPackage.(OPCPackage.java:141) at org.apache.poi.openxml4j.opc.ZipPackage.(ZipPackage.java:97) at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:324) at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:184) at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:149)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值