首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用 XML 与 Java NIO 的较量 如何转移话题至缓冲区和通道(1)

使用 XML 与 Java NIO 的较量 如何转移话题至缓冲区和通道(1)

用于那个站点的其中一个文档是一张参与者列表。由于那方面的内容已不属于本专栏的范围,所以用电子邮件程序将该列表作为通讯录来维护。令我头疼的是,这个文件的格式不是 XML。所以,我如何把它用于 XML 发布解决方案?我需要将这张列表转换成 XML。
编写一个专门的转换例程当然不困难,但这看起来象在浪费时间:因为还有其它需要把非-XML 文档用于 XML 解决方案的情况。除了通讯录,我可能还需要处理议程、电子表格、目录信息以及其它旧数据。
针对这个问题,XI 提供了一种普遍适用的解决方案。它使用正则表达式(现在已内置于 JDK 1.4 中)来解析输入文件并创建一个 XML 副本。我的上一篇专栏文章介绍了这些转换的详细信息以及 XI 的简短分析(请参阅 )。      
JDK 1.4 中的新特性我决定现在开发 XI 的原因之一是想要用已构建到 JDK 1.4 中的新的正则表达式(         regex )引擎进行实验。正如您将看到的,我所获得的远远超出了我在开始探究新 I/O 包(通常称为 NIO,它在包         java.nio 中)时所期待的。      
包 java.regex该正则表达式引擎有一个简单且清晰的接口,它主要要求您了解两个新类和一个新接口。这两个新类是         Pattern 和         Matcher ,而新接口是         CharSequence 。(后者可能会产生问题,我将在后面讨论它。)  说明了如何使用         Pattern 和         Matcher 。      
清单 1. 使用正则表达式引擎
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.util.regex.*;
public class SampleRegex
{
   public static void main(String[] params)
   {
      Pattern pattern =
        Pattern.compile("(.*).*)")
                 
        ;
      Matcher matcher =
        pattern.matcher(params[0])
                 
        ;
      if(
        matcher.matches()
                 
        )
      {
         System.out.print("Key:");
         System.out.println(
        matcher.group(1)
                 
        );
         System.out.print("Value:");
         System.out.println(matcher.group(2));
      }
      else
         System.out.print("No match");
   }
}




Pattern 是一个正则表达式编译器。它接受一个正则表达式并将它编译成         Matcher 。         Matcher 用于将正则表达式应用到字符串中,或者更确切地说,是应用到         CharSequence 中。      
Pattern 没有公共的构造函数。要创建         Pattern ,必须调用它的         compile() ,同时传递一个正则表达式作为参数。      
正则表达式 101正则表达式描述字符串的格式:使用最简单的正则表达式格式,您可以输入您希望匹配的文本。例如,正则表达式         ABC 将与字符串         ABC 匹配,但不与         DEF 匹配。      
当然,正则表达式被限定为严格的字符串比较。例如,可以使用称为        百搭(joker) ― 一个句点(         . )― 的通配符,它可以与一行中除了最后一个字符以外的任何一个字符相匹配。所以,正则表达式         A.C 将与字符串         ABC 、         AAC 、         AKC 以及许多其它字符串相匹配,但它依然不与         DEF 相匹配。      
字符或百搭后面的星号(         * )表明它可以与多个任意字符相匹配。因此,正则表达式         A*B 将与字符串         AB 、         AAB 、         AAAB 或以 A 开头并以单个 B 为结尾的任何其它字符串相匹配。      
由于句点是一个百搭,所以         .* 将与包括         ABC 、         IBM developerWorks 和         DEF 在内的任何字符串相匹配。      
圆括号用作分组操作符。它特别方便,因为正如您将看到的,从字符串中提取出一个组的内容是可能的。例如,  中使用的正则表达式         (.*).*) 与由冒号分隔开的两个字符串相匹配。      
有关正则表达式还有许多内容,我推荐您参考象        Mastering Regular Expressions那样的参考书(请参阅 )。      
Pattern 和 Matcher在  中,一旦将正则表达式编译成         Pattern ,它就创建了带         matcher() 方法的         Matcher 。         Matcher 接受         CharSequence (在下一节  中将对此作更详细的讨论)并报告正则表达式是否匹配。         Matcher 提供了几个方法来测试正则表达式:         matches() 、         lookingAt() 和         find() 。每个方法都可以应用正则表达式,但方式不同。      
Matcher 还提供了         group() 来检索与给定组相匹配的字符串。从 1 到         n 对组进行编号,而         group(0) 是一个完整的正则表达式。      
将正则表达式应用到命令行参数中。它打印找到的组(如果找到的话)。例如,用下面这条命令调用此应用程序:      
1
java SampleRegex "domain:ananas.org"




这时,它将打印:
1
2
Key: domain
Value: ananas.org




因为输入(         domain:ananas.org )与该正则表达式相匹配。然而,如果用下面这条命令调用此应用程序:      
1
java SampleRegex "ananas.org"




它将打印:
1
No match




因为输入不与正则表达式相匹配。
NIO我在前一节  中提到过         CharSequence 。这是定义在 java.lang 包中用于字符数组的新接口。对         String 已进行了更新以便实现         CharSequence 。      
更重要的是,通过使用 NIO 包,将一个文件作为         CharSequence 进行访问是可能的。因此,由于         Matcher 接受         CharSequence ,所以将正则表达式应用到全体文件是可能的。这就是我研究完 java.nio 包后得出的结论(请参阅参考资料)。      
最终,在这个项目中我没有使用 java.nio,但我仍然要讨论它,因为我在寻找解决方案时花了许多时间。(在软件开发中,钻牛角尖是一项非常有趣的消遣,如果我不对此进行报告,那么本专栏本身就不真实。另外,我希望我的经历将为您节省一些时间以避免进行相同的研究。)
向您演示了如何将文件转换成         CharSequence 。实际上,您最终可以使用         CharBuffer 这个新类,它对文本文件实现         CharSequence 。      
清单 2. 使用 CharBuffer
1
2
3
4
5
6
7
8
9
FileInputStream input = new FileInputStream(params[0]);
FileChannel channel = input.getChannel();
int fileLength = (int)channel.size();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY,0,fileLength);
Charset charset = Charset.forName("ISO-8859-1");
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode(buffer);
Matcher matcher = pattern.matcher(charBuffer);
// ...




在进一步讨论之前,我必须承认我不能确定我已经充分掌握了 NIO 背后的逻辑。我只是在最近才开始使用这个 API,这里只是我所掌握的。
正如您看到的,将文件转换成         CharBuffer 需要许多对象。这就是使用新 API 时的模式。就我所理解,NIO 的目的似乎是为了给您比常规 I/O 更多的控制和更大的灵活性。      
NIO 没有太多抽象的 API。例如,使用 Java IO,不必担心缓冲区管理,但您也不能对它进行控制。而 NIO 向您提供了对缓冲区管理的更多控制 ― 通过让您运行它!可以论证的是,它更有效,但它也更复杂。
当我在写这篇专栏文章时,我对 NIO 的印象是,它将对开发诸如数据库引擎、服务器和高性能客户机的高性能应用程序的人员特别有用。而对于常规编程,我认为没有必要使用 NIO(因为这要花额外的精力)。
而且,我使用 XI 的最终目标是使它与         XMLReader 保持兼容,因为它是由 SAX 定义的。         XMLReader 通常使用         InputStream 或         Reader ,但不使用 NIO。我没有找到一种完全普遍使用的解决方案来将任何         InputStream 转换成         CharBuffer 。(但我确实找到了部分解决方案。)如果您有更好的想法,请给我发电子邮件,我将在下一篇专栏文章中报告它。      
最后,我决定使用常规 I/O,将文件逐行地读取成字符串,并将正则表达式应用到那些字符串中。
返回列表