NIO区别于IO,是同步非阻塞的。nio直接使用native函数库,直接分配对外内存,通过DirectByteBuffer对象作为这块内存的引用操作,避免了数据在java堆和对外内存间来回复制。
主要组件:
Channel 通道,文件数据首先存在于channel中 可通过FileInputStream.getChannel()获取到channel
Buffer 缓冲区,数据可以从通道读入缓冲区,也可以将数据从缓冲区写到通道中
Select 用于管理一个或多个通道
nio读取文件示例
1 public class TestChannel { 2 public static void main(String[] args) throws IOException { 3 //读取到文件 4 RandomAccessFile f = new RandomAccessFile("C:\\test-nio.txt", "rw"); 5 //获取channel 6 FileChannel channel = f.getChannel(); 7 //分配缓存大小 8 ByteBuffer buffer = ByteBuffer.allocate(1024); 9 //从channel中读取数据循环读取到缓存中 10 int bytesRead = channel.read(buffer); 11 while (bytesRead != -1){ 12 System.out.println("before flip:"+buffer); 13 //切换为读模式,反转pos为0,使下一步get从0开始 14 buffer.flip(); 15 System.out.println("after flip:"+buffer); 16 while (buffer.hasRemaining()){ 17 System.out.print((char)buffer.get()); 18 } 19 //上一步打印完成后清除缓存内数据,使缓冲区可以再次被写入 20 buffer.clear(); 21 System.out.println("\nafter clear:"+buffer); 22 23 bytesRead = channel.read(buffer); 24 } 25 //关闭通道 26 channel.close();29 } 30 }
几个方法说明:
flip() 将buffer从写模式切换为读模式,是pos=0 limit=“写模式时最后的pos“。limit表示此缓冲区中最多可以读取的字节数
clear() 清空缓冲区,使pos=0 limit=capaticy
compact() 将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。注意和clear区分,clear不处理未读数据,直接清空
rewind() 将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少
mark()/reset() 通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position
scatter和gather:分散和聚合
1 public class TestScatterGather { 2 public static void main(String[] args) throws IOException { 3 RandomAccessFile raf = new RandomAccessFile("c:/test-nio.txt", "rw"); 4 FileChannel channel = raf.getChannel(); 5 6 ByteBuffer header = ByteBuffer.allocate(10); 7 ByteBuffer body = ByteBuffer.allocate(200); 8 9 ByteBuffer[] bufferArr = {header,body}; 10 long x = channel.read(bufferArr); 11 12 header.flip(); 13 while (header.hasRemaining()){ 14 System.out.print((char)header.get()); 15 } 16 header.clear(); 17 18 System.out.println("============"); 19 20 body.flip(); 21 while (body.hasRemaining()){ 22 System.out.print((char)body.get()); 23 } 24 body.clear(); 25 } 26 }