NIO 库是在 JDK 1.4 中引入的。在Java1.4之前的I/O系统中,提供的都是面向流的I/O系统,NIO 弥补了原来的 I/O 的不足,它在标准 Java 代码中提供了高速的、面向缓冲区的 I/O。通过定义包含数据的类,以及通过以块的形式处理这些数据,NIO 不用使用本机代码就可以利用低级优化,这是原来的 I/O 包所无法做到的。
java.NIO包里包括三个基本的组件:
1、buffer:因为NIO是基于缓冲的,所以buffer是最底层的必要类,这也是IO和NIO的根本不同,虽然stream等有buffer开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而NIO却是直接读到buffer中进行操作。因为读取的都是字节,所以在操作文字时,要用charset类进行编解码操作。
2、channel:类似于IO的stream,但是不同的是除了FileChannel,其他的channel都能以非阻塞状态运行。FileChannel执行的是文件的操作,可以直接DMA操作内存而不依赖于CPU。其他比如socketchannel就可以在数据准备好时才进行调用。
3、selector:用于分发请求到不同的channel,这样才能确保channel不处于阻塞状态就可以收发消息。
使用NIO实现读写:
在第一个练习中,将从一个文件中读取一些数据。如果使用原来的 I/O,那么只需创建一个 FileInputStream 并从它那里读取。而在 NIO 中,情况稍有不同:我们首先从 FileInputStream 获取一个 Channel 对象,然后使用这个通道来读取数据。在 NIO 系统中,任何时候执行一个读操作,都是从通道中读取,但是不是 直接 从通道读取。因为所有数据最终都驻留在缓冲区中,所以是从通道读到缓冲区中。因此读取文件涉及三个步骤:从 FileInputStream 获取 Channel、创建 Buffer、将数据从 Channel 读到 Buffer 中。
(1) 第一步是获取通道。从 FileInputStream 获取通道:
FileInputStream fin = new FileInputStream( "E:/nio.txt" );
FileChannel fc = fin.getChannel();
(2) 下一步是创建缓冲区
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
(3) 最后,需要将数据从通道读到缓冲区中,并输出控制台
fc.read( buffer );
buffer.flip();
while (buffer.hasRemaining()) {
// 读取buffer当前位置的整数
byte b = buffer.get();
System.out.print((char) b);
}
第二个练习,写入文件也包含三个步骤:从FileOutputStream获取Channel、创建Buffer并且把数据放到Buffer中、将Buffer中的数据写入Channel。
FileOutputStream fout = new FileOutputStream( "E:/nio.txt" );
FileChannel fc = fout.getChannel();
String str = "hello world!";
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
for (int i=0; i<str.length(); ++i) {
buffer.put( (byte) str.charAt(i) );
}
buffer.flip();
fc.write( buffer );
fout.close();