Java开发项目中经常会碰到处理Excel文件中数据的情况,这里通过一个例子来看一下实现方法:从Excel文件orders.xls中读取订单信息,从中找出2010年1月1日(含)之后,并且SELLERID等于18的订单。找到的数据写入order_result.xls文件。
Excel文件orders.xls的内容如下:
ORDERID CLIENT SELLERID AMOUNT ORDERDATE
1 UJRNP 17 392 2008/11/2 15:28
2 SJCH 6 4802 2008/11/9 15:28
3 UJRNP 16 13500 2008/11/5 15:28
4 PWQ 9 26100 2008/11/8 15:28
5 PWQ 11 4410 2008/11/12 15:28
6 HANAR 18 6174 2008/11/7 15:28
7 EGU 2 17800 2008/11/6 15:28
8 VILJX 7 2156 2008/11/9 15:28
9 JAYB 14 17400 2008/11/12 15:28
10 JAXE 19 19200 2008/11/12 15:28
11 SJCH 7 13700 2008/11/10 15:28
12 QUICK 11 21200 2008/11/13 15:28
13 HL 12 21400 2008/11/21 15:28
14 JAYB 1 7644 2008/11/16 15:28
15 MIP 16 3234 2008/11/19 15:28
16 AYWYN 4 6566 2008/11/21 15:28
Java程序的编写思路是
1、 从Excel文件逐行读入数据保存到List对象sourceList中。
2、 遍历List对象sourceList,如果满足条件就保存到结果List对象resultList中。
3、 遍历reslutList,逐行保存到输出Excel文件中。
其中包含一些处理不同数据类型的语句,具体代码如下:
publicstatic void myExcel() throws Exception {
//读excel数据
HSSFWorkbookworkbook=
newHSSFWorkbook(new FileInputStream(newFile("d:/file/orders.xls")));
Sheet sheet=workbook.getSheetAt(0);//读取第一个sheet
List<Map<String,Object>>sourceList= newArrayList<Map<String,Object>>();
List<Map<String,Object>>resultList=new ArrayList<Map<String,Object>>();
SimpleDateFormatformat = new SimpleDateFormat("yyyy-M-ddHH:mm:ss");
for(int i = 1; i <sheet.getPhysicalNumberOfRows(); i++) {//逐行处理excel数据
Row row=sheet.getRow(i);
Map<String,Object> order=newHashMap<String,Object>();
Cell cell0 = row.getCell(0);
cell0.setCellType(Cell.CELL_TYPE_STRING);
//整数数据要转为txt,否则会变成浮点数
Cellcell1 = row.getCell(1);
cell1.setCellType(Cell.CELL_TYPE_STRING);
Cellcell2 = row.getCell(2);
cell2.setCellType(Cell.CELL_TYPE_STRING);
order.put("ORDERID",cell0.toString());
order.put("CLIENT",cell1.toString());
order.put("SELLERID",cell2.toString());
order.put("AMOUNT",row.getCell(3).toString());
//处理日期类型的数据
order.put("ORDERDATE",
HSSFDateUtil.getJavaDate(row.getCell(4).getNumericCellValue()));
sourceList.add(order);
}
for(int i = 0, len = sourceList.size(); i <len; i++) {//按照条件过滤
Map<String,Object>order =(Map<String,Object>) sourceList.get(i);
System.out.println("1order.get(\"SELLERID\")="+order.get("SELLERID"));
if( Integer.parseInt(order.get("SELLERID").toString())==18 &&
((Date)order.get("ORDERDATE")).after(format.parse("2009-12-3123:59:59")) )
{//判断是否符合条件
resultList.add(order);//符合条件的加入List对象resultList
}
}
//写excel文件
HSSFWorkbookworkbook1 = new HSSFWorkbook();//创建excel文件对象
Sheetsheet1 = workbook1.createSheet();//创建sheet对象
Rowrow1;
row1= sheet1.createRow(0);//第一行,标题
row1.createCell(0).setCellValue("ORDERID");
row1.createCell(1).setCellValue("CLIENT");
row1.createCell(2).setCellValue("SELLERID");
row1.createCell(3).setCellValue("AMOUNT");
row1.createCell(4).setCellValue("ORDERDATE");
for(int i = 1, len = resultList.size(); i <len; i++) {//循环创建数据行
row1= sheet1.createRow(i);
row1.createCell(0).setCellValue(resultList.get(i).get("ORDERID").toString());
row1.createCell(1).setCellValue(resultList.get(i).get("CLIENT").toString());
row1.createCell(2).setCellValue(resultList.get(i).get("SELLERID").toString());
row1.createCell(3).setCellValue(resultList.get(i).get("AMOUNT").toString());
row1.createCell(4).setCellValue(format.format((Date)resultList.get(i).get("ORDERDATE")));
}
FileOutputStreamfos = newFileOutputStream("d:/file/orders_result.xls");
workbook1.write(fos);//写文件
fos.close();
}
程序执行后生成的excel文件数据如下:
ORDERID CLIENT SELLERID AMOUNT ORDERDATE
432 ERNSH 18 6272.0 2010-1-13 15:28:05
444 SJCH 18 4312.0 2010-1-25 15:28:05
452 HP 18 4312.0 2010-2-01 15:28:05
492 HP 18 27900.0 2010-3-07 15:28:05
512 BTMMU 18 18000.0 2010-3-27 15:28:05
524 PJIPE 18 15600.0 2010-4-09 15:28:05
637 HP 18 9114.0 2010-8-01 15:28:05
638 JOPO 18 294.0 2010-8-01 15:28:05
…
myExcel函数中有一多半代码是读写和处理Excel文件和数据类型的,比较复杂。条件过滤的代码虽然不多,但是却不够通用。过滤条件是固定的,如果有变化,就必须要改代码。如果希望变成动态过滤条件,那么就要写动态表达式解析程序了。理论上可以实现类似SQL那样灵活的过滤条件,但是程序比较难写,调试也比较复杂。
如果考虑采用集算器esProc作为辅助来实现Excel数据的处理,将会使这个程序的开发容易很多。esProc是专门为结构化(半结构化)数据设计的编程语言,可以写出比较简单的Excel文件处理程序。Java程序调用esProc脚本也非常简单。
程序员可以将条件“2010年1月1日(含)之后,并且SELLERID等于18的订单。”作为参数where传递给esProc程序,如下图:
Where的值是:ORDERDATE>=date(2010,1,1)&& SELLERID==18。esProc的程序代码如下:
A1:定义一个file对象,导入数据,第一行是标题。esProc的集成开发环境可以直观的显示出导入的数据,如上图右边部分。如果访问xlsx文件,可以写成=file("D:/file/orders.xlsx")[email protected]()。
A2:按照条件过滤。这里使用宏来实现动态解析表达式,其中的where就是传入参数。集算器将先计算${…}里的表达式,将计算结果作为宏字符串值替换${…}之后解释执行。这个例子中最终执行的是:=A1.select(ORDERDATE>=date(2010,1,1) && SELLERID==18)。
A3:将符合条件的结果集写入excel文件。
过滤条件发生变化时不用改变程序,只需改变where参数即可。例如,条件变为:2010年1月1日(含)之后,并且SELLERID等于18的订单,或者CLIENT等于PWQ的订单。Where的参数值可以写为:CLIENT=="PWQ"||ORDERDATE>=date(2010,1,1) && SELLERID==18。执行之后,A2中的结果集如下图:
我们可以在Java程序中调用这段esProc程序,使用esProc提供的jdbc即可完成。将上述esProc程序保存为test.dfx文件的话,Java调用的代码如下:
//建立esProcjdbc连接
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
//调用esProc程序(存储过程),其中test是dfx的文件名
com.esproc.jdbc.InternalCStatementst=(com.esproc.jdbc.InternalCStatement)con.createStatement();
//设置参数
st.setObject(1,"ORDERDATE>=date(2010,1,1)&& SELLERID==18 || CLIENT==\"PWQ\"");//参数就是动态的过滤条件
//执行esProc存储过程
st.execute();
对于这种代码较简单的脚本,还可以直接把集算器代码写在调用集算器JDBC的Java程序中,而不必专门编写集算器脚本文件(test.dfx):
String where="CLIENT==\"PWQ\"||ORDERDATE>=date(2010,1,1)&& SELLERID==18 ";
String resultpath="D:/file/orders_result.xls ";
String sourcepath=" D:/file/orders.xls";
ResultSet set =st.executeQuery("=file(\""+resultpath+"\")[email protected](file(\""+sourcepath+"\")[email protected]().select("+where+"))");
这段Java代码直接调用了集算器的一句脚本:从Excel文件中取得数据,并按照指定的条件过滤。结果集写入结果Excel文件。