java的nio的使用示例分享
本文导语: Java NIO(New Input/Output)——新的输入/输出API包——是2002年引入到J2SE 1.4里的。Java NIO的目标是提高Java平台上的I/O密集型任务的性能。过了十年,很多Java开发者还是不知道怎么充分利用NIO,更少的人知道在Java SE 7里引入了更新的输...
Java NIO(New Input/Output)——新的输入/输出API包——是2002年引入到J2SE 1.4里的。Java NIO的目标是提高Java平台上的I/O密集型任务的性能。过了十年,很多Java开发者还是不知道怎么充分利用NIO,更少的人知道在Java SE 7里引入了更新的输入/输出 API(NIO.2)。NIO和NIO.2对于Java平台最大的贡献是提高了Java应用开发中的一个核心组件的性能:输入/输出处理。不过这两个包都不是很好用,并且它们也不是适用于所有的场景。如果能够正确地使用的话,Java NIO和NIO.2可以大大减少一些常用I/O操作所花的时间。这就是NIO和NIO.2所具有的超能力,我会在这篇文章里向你展示5种使用它们的简单方式。
变更通知(因为每个事件都需要一个监听者)
选择器和异步IO:通过选择器来提高多路复用
通道——承诺与现实
内存映射——好钢用在刀刃上
字符编码和搜索
NIO的背景
为什么一个已经存在10年的增强包还是Java的新I/O包呢?原因是对于大多数的Java程序员而言,基本的I/O操作都能够胜任。在日常工作中,大部分的Java开发者没有必要去学习NIO。更进一步,NIO不仅仅是一个性能提升包。相反,它是一个和Java I/O相关的不同功能的集合。NIO通过使得Java应用的性能“更加接近实质”来达到性能提升的效果,也就是意味着NIO和NIO.2的API暴露了低层次的系统操作的入口。NIO的代价就是它在提供更强大的I/O控制能力的同时,也要求我们比使用基本的I/O编程更加细心地使用和练习。NIO的另一特点是它对于应用程序的表现力的关注,这个我们会在下面的练习中看到。
开始学习NIO和NIO.2
NIO的参考资料非常多——参考资料中选取的一些链接。要学习NIO和NIO.2的话,Java 2 SDK Standard Edition(SE) documentation 和 Java SE 7 documentation 都是不可或缺的。要使用这篇文章里的代码,你需要使用JDK 7或者更高的版本。
对于很多开发者而言,它们第一次遇到NIO都可能是在维护应用的时候:一个功能正常的应用响应越来越慢,因此有人建议使用NIO来提高响应速度。NIO在提升应用性能的时候显得比较出众,不过具体的结果取决于底层系统.(注意NIO是平台相关的)。如果你是第一次使用NIO的话,你需要仔细衡量。你会发现NIO提升性能的能力不仅仅取决于OS,同时也取决于你所使用的JVM,主机的虚拟上下文,大容量存储的特性甚至和数据也是相关的。因此,性能衡量的工作是比较难做的。尤其是当你的系统存在一个可移动的部署环境的时候,你需要特别注意。
了解了上面的内容后,我们没有后顾之忧了,现在就来体验一下NIO和NIO.2的5个重要的功能。
1. 变更通知(因为每个事件都需要一个监听者)
对NIO和NIO.2有兴趣的开发者的共同关注点在于Java应用的性能。根据我的经验,NIO.2里的文件变更通知者(file change notifier)是新输入/输出API里最让人感兴趣(被低估了)的特性。
很多企业级应用需要在下面的情况时做一些特殊的处理:
当一个文件上传到一个FTP文件夹里时
当一个配置里的定义被修改时
当一个草稿文档被上传时
其他的文件系统事件出现时
这些都是变更通知或者变更响应的例子。在Java(以及其他语言)的早期版本里,轮询(polling)是检测这些变更事件的最好方式。轮询是一种特殊的无限循环:检查文件系统或者其他对象,并且和之前的状态对比,如果没有变化,在大概几百个毫秒或者10秒的间隔后,继续检查。就这一直无限循环下去。
NIO.2提供了一个更好地方式来进行变更检测。列表1是一个简单的示例。
列表1. NIO.2里的变更通知机制
import java.nio.file.attribute.*;
importjava.io.*;
importjava.util.*;
importjava.nio.file.Path;
importjava.nio.file.Paths;
importjava.nio.file.StandardWatchEventKinds;
importjava.nio.file.WatchEvent;
importjava.nio.file.WatchKey;
importjava.nio.file.WatchService;
importjava.util.List;
publicclassWatcher{
publicstaticvoidmain(String[]args){
Paththis_dir=Paths.get(".");
System.out.println("Nowwatchingthecurrentdirectory...");
try{
WatchServicewatcher=this_dir.getFileSystem().newWatchService();
this_dir.register(watcher,StandardWatchEventKinds.ENTRY_CREATE);
WatchKeywatckKey=watcher.take();
List