直接用Java实现文本文件排序,对于小文件还较为简单,如果是内存装不下的大文件,需要分段读入数据,再将每段排序结果写成临时文件,最后归并这些临时文件,编程非常复杂。即使只处理内存可放下的小文件,也要面对解析文本中数据类型的任务,虽然不是很难,但要写较长的代码。
使用集算器辅助java编程就可以轻松规避这些问题。下面我们来看一下具体作法。文本文件employee.txt中保存的员工信息,需要按照STATE的升序和BIRTHDAY的降序排序。假设文件中的数据量较大,内存不能一次装入。
empolyee.txt的格式如下:
EID NAME SURNAME GENDER STATE BIRTHDAY HIREDATE DEPT SALARY
1 Rebecca Moore F California 1974-11-20 2005-03-11 R&D 7000
2 Ashley Wilson F New York 1980-07-19 2008-03-16 Finance 11000
3 Rachel Johnson F New Mexico 1970-12-17 2010-12-01 Sales 9000
4 Emily Smith F Texas 1985-03-07 2006-08-15 HR 7000
5 Ashley Smith F Texas 1975-05-13 2004-07-30 R&D 16000
6 Matthew Johnson M California 1984-07-07 2005-07-07 Sales 11000
7 Alexis Smith F Illinois 1972-08-16 2002-08-16 Sales 9000
8 Megan Wilson F California 1979-04-19 1984-04-19 Marketing 11000
9 Victoria Davis F Texas 1983-12-07 2009-12-07 HR 3000
10 Ryan Johnson M Pennsylvania 1976-03-12 2006-03-12 R&D 13000
11 Jacob Moore M Texas 1974-12-16 2004-12-16 Sales 12000
12 Jessica Davis F New York 1980-09-11 2008-09-11 Sales 7000
13 Daniel Davis M Florida 1982-05-14 2010-05-14 Finance 10000
…
实现的思路是:用Java程序调用集算器脚本,读取和计算数据,之后将结果以ResultSet的方式返回给Java程序。要按照STATE的升序和BIRTHDAY的降序排序,esProc程序可以从外部获得一个输入参数“sortBy”作为排序表达式,如下图:
“sortBy”的值是:STATE,-BIRTHDAY。字段前面加上减号代表相反数,对于字符串、数值和日期类型数据都是有效的。
esProc代码如下:
A1:定义一个file游标对象,第一行是标题,字段分隔符默认是tab。
A2:按照表达式来排序。这里使用宏来实现动态解析表达式,其中的sortBy就是传入参数。集算器先计算${…}里的表达式,将计算结果作为宏字符串值替换${…}之后解释执行。这个例子中最终执行的是:=A1.sortx(STATE,-BIRTHDAY;1000000)。
A3:向外部程序返回结果游标。Java使用ResultSet接受返回结果遍历数据的时候,集算器会自动读取游标对应的内容。如果要将排序数据写入其他文件,则把A3改为=file("D:/employee_result.txt").export@t(A2)。
排序字段和方向发生变化时不用改变程序,只需改变sortBy参数即可。例如,按照NAME的升序、STATE的降序、BIRTHDAY的降序排序,sortBy值写为:NAME,-STATE,-BIRTHDAY。
sortx函数按照缓冲区行数每次读取部分数据来排序,结果写入临时文件,并重新利用内存。之后,再将生成的临时文件归并。这里的参数1000000就是指缓冲行数,取值原则是充分利用内存以减少临时文件数量。这个数值和物理内存及记录的大小都有关,编程时要估算一下,一般建议在几十万到上百万的量级。
在Java程序中通过集算器的jdbc调用这段esProc程序(保存为test.dfx文件)的代码如下:
//建立esProc jdbc连接
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
//调用esProc 程序(存储过程),其中test是dfx的文件名
st =(com.esproc.jdbc.InternalCStatement)con.prepareCall("call test(?)");
//设置参数
st.setObject(1," NAME,-STATE,-BIRTHDAY");
//执行esProc存储过程
st.execute();
//获取结果集:符合条件的员工集合
ResultSet set = st.getResultSet();
对于较简单的脚本,还可以直接把代码写在调用集算器JDBC的Java程序中,而不必专门编写集算器脚本文件(test.dfx):
st=(com. esproc.jdbc.InternalCStatement)con.createStatement();
ResultSet set = st.executeQuery("=file(\"D:/employee.txt\").cursor@t().sortx(NAME,-STATE,BIRTHDAY;1000000)");
这段Java代码直接调用了集算器的一句脚本:从文本文件中取得数据计算后,结果集返回给ResultSet对象set。
如果employee.txt文件较小,能够一次装入内存,可以改用sort函数来做全内存排序,集算器不再写临时文件,计算速度要快很多。代码如下:
sortBy参数可以写成STATE,-BIRTHDAY,也可以写成:STATE:1,BIRTHDAY:-1。Java调用的程序不用修改。