程序开发中经常会碰到处理文本文件中数据的情况,这里通过一个例子来看用 java 实现文本文件按条件过滤的方法:从文本文件 employee.txt 中读取员工信息,从中找出 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

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 程序的编写思路是从文件逐行读入数据保存到 List 对象中,再遍历 List 对象,如果满足条件就保存到结果 List 对象中,最后打印出符合条件的员工个数。具体代码如下:

public static void myFilter() throws Exception{

File file = newFile("D:\\employee.txt");

FileInputStream fis = null;

fis = new FileInputStream(file);

InputStreamReader input = newInputStreamReader(fis);

BufferedReader br = newBufferedReader(input);

String line = null;

String info[] = null;

List sourceList= new ArrayList();

List resultList= new ArrayList();

if ((line = br.readLine())== null)return;// 第一行舍弃,如果文件为空则退出

while((line = br.readLine())!= null){// 从文件中读入到内存中

info =line.split("\t");

Map<String,String>emp=new HashMap<String,String>();

emp.put("EID",info[0]);

emp.put("NAME",info[1]);

emp.put("SURNAME",info[2]);

emp.put("GENDER",info[3]);

emp.put("STATE",info[4]);

emp.put("BIRTHDAY",info[5]);

sourceList.add(emp);

}

for (int i = 0, len =sourceList.size(); i < len; i++) {// 逐行处理数据

Map<String,String> emp=(Map) sourceList.get(i);

SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd");

if (emp.get("GENDER").equals("F") &&!sdf.parse(emp.get("BIRTHDAY")).before(sdf.parse("1981-01-01")))

{ // 条件判断语句,符合条件的加入 List 对象

resultList.add(emp);

}

}

System.out.println("count="+resultList.size());// 打印员工个数

}

这个函数的过滤条件是固定的,如果条件发生了变化,需要修改程序中的条件判断语句, 多种条件就写多段代码,无法处理临时性的动态条件 。下面改造一下这个代码,让它具备一定的通用性。只有遍历 sourceList 的循环有所改变:

for (int i = 0, len = sourceList.size(); i <len; i++) {

Map<String,String> emp=(Map) sourceList.get(i);

SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd");

boolean isRight = true;

if (gender!=null &&!emp.get("GENDER").equals(gender)){// 处理性别条件

isRight = false;

}

if (start!=null && sdf.parse(emp.get("BIRTHDAY")).before(start)){// 处理生日的起始条件

isRight = false;

}

if (end!=null &&sdf.parse(emp.get("BIRTHDAY")).after(end) ){// 处理生日的结束条件

isRight = false;;

}

if (isRight)resultList.add(emp);// 符合条件的记录加入结果 list

}

改写之后的代码中, gender、start、end 是函数 myFilter 的输入参数。程序可以处理 GENDER 字段等于输入值 gender,BIRTHDAY 字段大于等于输入值 start ,小于等于输入值 end 的情况。如果任何一个输入值为 null ,这个条件就不参与过滤。条件之间是 AND 关系。

如果希望 myFilter 更通用,比如:条件之间 OR 关系,或者字段之间发生了运算,那么代码就会更复杂了,需要编写动态表达式解析和求值的程序。这样的程序虽然可以像数据库的 SQL 那样灵活和通用,但编写难度实在是太大了。

这种情况下,可以采用用集算器 esProc 来辅助完成这个任务。集算器是专门为结构化(半结构化)数据处理设计的开发语言,实现上述通用查询任务很轻松,并和 Java 程序能无缝结合,从而使 Java 程序可以象 SQL 那样灵活访问和处理文本文件中的数据。

例如,我们需要查询 1981 1 1 日(含)之后出生的女员工, esProc 程序可以从外部传入一个输入参数“ where ”作为动态的条件,如下图:

Java实现文本文件按条件过滤的简便方法_文本文件

where ”的值是: BIRTHDAY>=date(1981,1,1)&& GENDER=="F" 。具体的 esProc 代码只需要三行,如下:

Java实现文本文件按条件过滤的简便方法_文本文件_02

A1 :定义一个 file 对象,导入数据,第一行是标题,字段分隔符默认是 tab esProc 的集成开发环境可以直观的显示出导入的数据,如上图右边部分。

A2 :按照条件过滤。这里使用宏来实现动态解析表达式,其中的 where 就是传入参数。 集算器将先计算 ${…} 里的表达式,将计算结果作为宏字符串值替换 ${…} 之后解释执行。 这个例子中最终执行的是: =A1.select(BIRTHDAY>=date(1981,1,1)&& GENDER=="F")

A3 :向外部程序返回符合条件的结果集。

过滤条件发生变化时不用改变程序,只需改变 where 参数即可。例如,条件变为: 查询 1981 1 1 日(含)之后出生的女员工,或者 NAME+SURNAME 等于 ”RebeccaMoore” 的员工。 Where 的参数值可以写为: BIRTHDAY>=date(1981,1,1)&& GENDER=="F" || NAME+SURNAME=="RebeccaMoore" 。执行之后, A2 中的结果集如下图:

Java实现文本文件按条件过滤的简便方法_条件过滤_03

最后,还需要在 Java 程序中调用这段 esProc 程序获得过滤结果,使用 esProc 提供的 jdbc 即可完成。将上述 esProc 程序保存为 test.dfx 文件的话, Java 调用的代码如下:

// 建立 esProc jdbc 连接

Class.forName("com.esproc.jdbc.InternalDriver");

con= DriverManager.getConnection("jdbc:esproc:local://");

// 调用 esProc 程序(存储过程),其中 test dfx 的文件名

st =(com.esproc.jdbc.InternalCStatement)con.prepareCall("calltest(?)");

// 设置参数

st.setObject(1,"BIRTHDAY>=date(1981,1,1) && GENDER==\"F\" ||NAME+SURNAME==\"RebeccaMoore\"");// 参数就是动态的过滤条件

// 执行 esProc 存储过程

st.execute();

// 获取结果集:符合条件的员工集合

ResultSet set = st.getResultSet();

对于代码较简单的脚本,还可以直接把集算器代码写在调用集算器 JDBC Java 程序中,而不必专门编写集算器脚本文件( test.dfx ):

st=(com. esproc.jdbc.InternalCStatement)con.createStatement();

ResultSetset=st.executeQuery("=file(\"D:\\\\esProc\\\\employee.txt\") .import@t().select(BIRTHDAY>=date(1981,1,1) &&GENDER==\"F\"|| NAME+SURNAME==\"RebeccaMoore\")");

这段 Java 代码直接调用了集算器的一句脚本:从文本文件中取得数据,并按照指定的条件过滤。结果集返回给 ResultSet 对象 set