上一篇文章写了I/O,这篇文章介绍一下NIO:
在软件系统中,由于I/O的速度要比内存的速度慢,因此,I/O读写在很多时候会成为系统的瓶颈。
上一篇文章我们介绍了inputStream和outputStream,以字节为单位处理数据,这样就非常容易建立过滤器。NIO是new I/O的简称,在java 1.4中被纳入到JDK中并具有一些特性:
-
为所有的原始类型提供(Buffer)缓存
-
使用java.nio.charset.Charset作为字符集编码解码解决方案
-
增加通道(channel) 对象,作为新的原始I/O抽象
-
支持锁和内存映射文件的文件访问接口
-
提供了基于Selector的已不用网络I/O
与流试I/O不同,NIO是基于块(Block)的,它以块为基础的单位处理数据,在NIO中最为重要的两个组件为缓冲(Buffer),通道(channel),缓冲是一块连续的内存块,是NIO读写数据的中转地,通道表示缓冲数据的源头或者目的地,它用于向缓冲读取或者写入数据,是缓冲访问的接口。
下面说一下缓冲(Buffer),大家理解了这个就更容易理解下边的说明了:
缓冲(Buffer):是内存中一块特定的区域,开辟缓冲的目的是缓解应用程序上下层之间的性能差异,提高系统的性能,缓冲的一个典型应用就是漏斗,如图:
图片截取自葛一鸣的《java程序性能优化一书》
注意:缓冲可以协调上层组件和下层组件之间的性能差,当上层组件性能优于下层组件的时候,可以有效减少上层组件对下层组件的等待时间。
基于这样的结构,上层应用组件不需要等待下层组件真实的接受全部数据,即可返回操作,加快了上层组件的处理速度,从而提升系统性能。
Channel是一个双向通道,即可读,也可写,但是读写操作必须经过buffer,比如,在读一个Channel的时候,需要先将数据读入到Buffer,然后在Buffer中读取。
这是我画的一个图,大家理解一下:
根据上图写一个简单的读文件示例:
/**
* NIO文件复制(为了直观看代码,直接将异常抛出)
* @author 小白程序员
*
*/
public class nioCopyFile {
public static void main(String[] args) throws IOException {
String InFilePath = "E://InFileTest.txt";// 源文件
String OutFilePath = "E://OutFileTest.txt"; // 目标文件
FileInputStream in = new FileInputStream(InFilePath);
FileOutputStream out = new FileOutputStream(OutFilePath);
FileChannel readChannel = in.getChannel(); // 读文件操作
FileChannel writeChannel = out.getChannel();// 写文件操作
// 读入数据缓存,使用静态方法从堆中分配缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);//
while(true){
buffer.clear();// 为读入到buffer做准备
int len = readChannel.read(buffer); // 从通道读入数据,放到buffer中
if(len == -1){
break;
}
buffer.flip();// 将buffer将写状态转为读状态
writeChannel.write(buffer);// 从通道读出数据,写到out中
}
readChannel.close();
writeChannel.close();
System.out.println("NIO复制文件完毕!!!");
}
}
这个通过NIO复制文件的例子,大家一定要自己写一遍才有体会。
这篇文章的部分内容借鉴于葛一鸣的《java程序性能优化 》一书,也推荐大家去买过来好好看看,里边包括好多的性能优化篇幅。