技术开发 频道

实战 Groovy: for each 剖析

  文件迭代

  我从未想过使用原始的 Java 代码逐行遍历 java.io.File。当我完成了所有的嵌套的 BufferedReader 和 FileReader 后(更别提每个流程末尾的所有异常处理),我已经忘记最初的目的是什么。

  清单 18 展示了使用 Java 语言完成的整个过程:

  清单 18. Java 文件迭代  

import java.io.BufferedReader;

  import java.io.FileNotFoundException;

  import java.io.FileReader;

  import java.io.IOException;

  
public class WalkFile {

  
public static void main(String[] args) {

  BufferedReader br
= null;

  try {

  br
= new BufferedReader(new FileReader("languages.txt"));

  
String line = null;

  
while((line = br.readLine()) != null) {

  System.out.println(
"I know " + line);

  }

  }

  catch(FileNotFoundException e) {

  e.printStackTrace();

  }

  catch(IOException e) {

  e.printStackTrace();

  }

  finally {

  
if(br != null) {

  try {

  br.close();

  }

  catch(IOException e) {

  e.printStackTrace();

  }

  }

  }

  }

  }

  清单 19 展示了 Groovy 中的等效过程:

  清单 19. Groovy 文件迭代  

def f = new File("languages.txt")

  f.eachLine{language
->

  println
"I know ${language}"

  }

  这正是 Groovy 的简洁性真正擅长的方面。现在,我希望您了解为什么我将 Groovy 称为 “Java 程序员的 DSL”。

  注意,我在 Groovy 和 Java 语言中同时处理同一个 java.io.File 类。如果该文件不存在,那么 Groovy 代码将抛出和 Java 代码相同的 FileNotFoundException 异常。区别在于,Groovy 没有已检测的异常。在 try/catch/finally 块中封装 eachLine() 结构是我自己的爱好 — 而不是一项语言需求。对于一个简单的命令行脚本中,我欣赏 清单 19 中的代码的简洁性。如果我在运行应用服务的同时执行相同的迭代,我不能对这些异常坐视不管。我将在与 Java 版本相同的 try/catch 块中封装 eachLine() 块。

  File 类对 each() 方法进行了一些修改。其中之一就是 splitEachLine(String separator, Closure closure)。这意味着您不仅可以逐行遍历文件,同时还可以将它分为不同的标记。清单 20 展示了一个例子:

  清单 20. 分解文件的每一行 

 // languages.txt

  
// notice the space between the language and the version

  Java
1.5

  Groovy
1.6

  JavaScript
1.x

  
// splitTest.groovy

  def f
= new File("languages.txt")

  f.splitEachLine(
" "){words->

  words.each{ println it }

  }

  
// output

  Java

  
1.5

  Groovy

  
1.6

  JavaScript

  
1.x

  如果处理的是二进制文件,Groovy 还提供了一个 eachByte() 方法。

  当然,Java 语言中的 File 并不总是一个文件 — 有时是一个目录。Groovy 还提供了一些 each() 修改以处理子目录。

0
相关文章