集算器協(xié)助Java處理結(jié)構(gòu)化文本之條件過(guò)濾
直接用Java實(shí)現(xiàn)文本文件中數(shù)據(jù)按條件過(guò)濾會(huì)有如下的麻煩:
1、文件不是數(shù)據(jù)庫(kù),不能用SQL訪問(wèn)。當(dāng)過(guò)濾條件變化時(shí)需要改寫(xiě)代碼。如果要實(shí)現(xiàn)象SQL那樣靈活的條件過(guò)濾,則需要自己實(shí)現(xiàn)動(dòng)態(tài)表達(dá)式解析和求值,編程工作量非常大。
2、文件太大時(shí)不能一次性裝入內(nèi)存處理,而采用逐步讀入方式在考慮到性能時(shí)又會(huì)涉及到文件緩沖區(qū)管理、拆行計(jì)算等復(fù)雜編程。
使用集算器來(lái)輔助Java編程,這些問(wèn)題都不需要自己寫(xiě)代碼解決。下面我們通過(guò)例子來(lái)看一下具體作法。
文本文件employee.txt中保存了員工數(shù)據(jù)。我們要讀取員工信息,從中找出1981年1月1日(含)之后出生的女員工。
文本文件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
***shley 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
…
實(shí)現(xiàn)的思路是:用Java程序調(diào)用集算器腳本,讀取和計(jì)算數(shù)據(jù),之后將結(jié)果以ResultSet的方式返回給Java程序。由于集算器支持動(dòng)態(tài)表達(dá)式解析和求值,使得Java程序可以像使用sql那樣,靈活的過(guò)濾文本文件中的數(shù)據(jù)。
例如,我們需要查詢1981年1月1日(含)之后出生的女員工,esProc程序可以從外部獲得一個(gè)輸入?yún)?shù)“where”作為條件,如下圖:
where是個(gè)字串,取值是:BIRTHDAY>=date(1981,1,1) && GENDER==”F”。
esProc代碼如下:
A1:定義一個(gè)file對(duì)象,讀入數(shù)據(jù),***行是標(biāo)題,字段分隔符默認(rèn)是tab。esProc的集成開(kāi)發(fā)環(huán)境可以直觀的顯示出導(dǎo)入的數(shù)據(jù),如上圖右邊部分。
A2:按照條件過(guò)濾。這里使用宏來(lái)實(shí)現(xiàn)動(dòng)態(tài)解析表達(dá)式,其中的where就是傳入?yún)?shù)。集算器先計(jì)算${…}里的表達(dá)式,將計(jì)算結(jié)果作為宏字符串值 替換${…}之后解釋執(zhí)行。這個(gè)例子中最終執(zhí)行的是:=A1.select(BIRTHDAY>=date(1981,1,1) && GENDER==”F”)。
A3:向外部程序返回符合條件的結(jié)果集。
過(guò)濾條件發(fā)生變化時(shí)不用改變代碼,只需改變where參數(shù)即可。例如,條件變?yōu)椋翰樵?981年1月1日(含)之后出生的女員工,或者 NAME+SURNAME等于”RebeccaMoore”的員工。Where的參數(shù)值可以寫(xiě) 為:BIRTHDAY>=date(1981,1,1) && GENDER==”F” || NAME+SURNAME==”RebeccaMoore”。執(zhí)行之后,A2中的結(jié)果集如下圖:
在Java程序中使用esProc JDBC調(diào)用這段程序獲得結(jié)果的代碼如下:(將上述esProc程序保存為test.dfx):
//建立esProc jdbc連接
Class.forName(“com.esproc.jdbc.InternalDriver”);
con= DriverManager.getConnection(“jdbc:esproc:local://”);
//調(diào)用esProc 程序(存儲(chǔ)過(guò)程),其中test是dfx的文件名
st =(com.esproc.jdbc.InternalCStatement)con.prepareCall(“call test(?)”);
//設(shè)置參數(shù)
st.setObject(1,” BIRTHDAY>=date(1981,1,1) && GENDER==\”F\” ||NAME+SURNAME==\”RebeccaMoore\”");//參數(shù)就是動(dòng)態(tài)的過(guò)濾條件
//執(zhí)行esProc存儲(chǔ)過(guò)程
st.execute();
//獲取結(jié)果集:符合條件的員工集合
ResultSet set = st.getResultSet();
對(duì)于代碼較簡(jiǎn)單的腳本,還可以把代碼直接寫(xiě)在調(diào)用集算器JDBC的Java程序中,而不必專(zhuān)門(mén)編寫(xiě)腳本文件(test.dfx):
st=(com. esproc.jdbc.InternalCStatement)con.createStatement();
ResultSet set= st.executeQuery(“=file(\”D:/employee.txt\”).import@t().select(BIRTHDAY>=date(1981,1,1)&&GENDER==\”F\” || NAME+SURNAME==\”RebeccaMoore\”)”);
這段Java代碼直接調(diào)用了集算器的一句腳本:從文本文件中取得數(shù)據(jù),并按照指定的條件過(guò)濾。結(jié)果集返回給ResultSet對(duì)象set。
上面方法中假定文件較小,可以全部讀入內(nèi)存。但實(shí)際上可能發(fā)生文件較大無(wú)法讀入內(nèi)容的情況,而且即使可以讀入也沒(méi)必要占太多內(nèi)存,這時(shí)可以使用文件游標(biāo)的方式來(lái)處理。集算器程序調(diào)整如下:
A1:定義一個(gè)file對(duì)象游標(biāo),***行是標(biāo)題,字段分隔符默認(rèn)是tab。
A2:按照條件過(guò)濾游標(biāo)。這里使用宏來(lái)實(shí)現(xiàn)動(dòng)態(tài)解析表達(dá)式,其中的where就是傳入?yún)?shù)。集算器將先計(jì)算${…}里的表達(dá)式,將計(jì)算結(jié)果作為宏字 符串值替換${…}之后解釋執(zhí)行。這個(gè)例子中最終執(zhí)行的是:=A1.select(BIRTHDAY>=date(1981,1,1) && GENDER==”F”)。
A3:返回游標(biāo)。
雖然集算器給Java返回的是游標(biāo),但是Java調(diào)用的程序不用修改。在Java使用ResultSet遍歷數(shù)據(jù)的時(shí)候集算器會(huì)自動(dòng)取出游標(biāo)對(duì)應(yīng)的內(nèi)容。
如果需要將過(guò)濾后的數(shù)據(jù)寫(xiě)入另一個(gè)文件而不是返回給主程序,只要將A3格的表達(dá)式改成:=file(“D:/employee_group.txt”).export@t(A2)即可,集算器將把游標(biāo)數(shù)據(jù)寫(xiě)出成文件。