NIO的使用
一)、什么叫NIO?
定义:是一套新的Java I/O标准, 在java1.4中被纳入JDK中。
二)、NIO的实现方法
NIO是基于块的, 以块为基本单位处理数据。
标准的I/O是基于流实现的,以字节为单位处理数据。
三)、NIO的特性
1).为所有的原始类型特供Buffer支持
ByteBuffer CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer ShortBuffer
2).字符集编码解码解决方案,使用java.nio.Charset
3) .增加通道(Channel)对象,做为新的原始的I/O抽象
4).支持锁和内存映射文件的文件访问接口
5).提供了基于Selector的异步网络I/O
四)、NIO的两个重要组件
Buffer: 缓冲, 是一块连续的内存块,是NIO中读写数据的中转地。
Channel: 通道, 表示缓冲数据的源头或目的地。
Buffer和Channel的关系:
Channel作为数据的源头:从Channel中写数据到Buffer
Channel ---------> Buffer
Channel作为数据的目的地:从Buffer中写出数据到Channel
Channel <--------- Buffer
五)、NIO的Buffer类族和Channel
Buffer: 是一个抽象类,JDK为每一种Java原生类型都创建了一个Buffer.
注: 除了ByteBuffer外,其它每一种Buffer都具有完全一样的操作。
原因:ByteBuffer多用于绝大多数数标准I/O操作的接口。
Channel: 是一个双向通道,既可读也可写。
注:应用程序中不能直接对Channel进行读写操作,在读取Channel时,需要先将数据读入到相对应的Buffer中,然后在Buffer中进行读取。
使用Buffer读取文件:
public class Nio_Buffer_Channel { public static void main(String[] args) throws IOException { //获取一个输入流对象 FileInputStream fin = new FileInputStream("d:/a.txt"); //获取输入流对象的通道,作为数据的源头 FileChannel fileChannel = fin.getChannel(); //创建一个Buffer对象 ByteBuffer buffer = ByteBuffer.allocate(1024); //从通道中读取数据到Buffer中 fileChannel.read(buffer); //关闭通道 fileChannel.close(); buffer.flip(); } }
使用Buffer完成文件的复制:
public class Nio_Buffer_Copy { public static void main(String[] args) throws IOException { //输出流对象 FileOutputStream fout = new FileOutputStream("d:/c.txt"); //输入流对象 FileInputStream fin = new FileInputStream("d:/a.txt"); //输出流的通道,数据的目的地 FileChannel writeChannel = fout.getChannel(); //输入流的通道,数据的源头 FileChannel readChannel = fin.getChannel(); //Buffer对象 ByteBuffer buffer = ByteBuffer.allocate(1024); while(true){ buffer.clear(); //返回读取数据的大小 int len = readChannel.read(buffer); if(len == -1){ break; } buffer.flip(); writeChannel.write(buffer); } } }
结果:
0 11 0 11 0
六)、深入学习Buffer
主要属性:
//标志位 private int mark = -1; //写模式:当前缓冲区的位置,从Position的下一个位置写数据 //读模式:当前缓冲区的读位置,将从此位置后,读取数据 private int position = 0; //写模式: 缓冲区的实际上限,总是小于等于容量,通常等于容量 //读模式: 代表可读取的总容量,和上次写入的数据量相等 private int limit; //写模式: 缓冲区的总容量上限 //读模式: 缓冲区的总容量上限 private int capacity;
对Buffer进行claer()和flip()操作时lmint和position的变化
public class Filp_Clear { public static void main(String[] args) { //创建具有15个字节的Buffer对象 ByteBuffer buffer = ByteBuffer.allocate(15); System.out.println("存入元素后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity()); //向Buffer中存入数据 for(int i = 0 ; i < 10 ; i++){ buffer.put((byte)i); } //存入元素后position和limit的变化 System.out.println("存入元素后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity()); buffer.flip(); //flip后position和limit的变化 System.out.println("flip后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity()); for(int i = 0 ; i < 5 ; i++){ System.out.print(buffer.get()+" "); } System.out.println(); //读取Buffer元素后position和limit的变化 System.out.println("读取Buffer元素后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity()); buffer.rewind(); System.out.println("rewind==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity()); buffer.flip(); //第二次flip后position和limit的变化 System.out.println("第二次flip后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity()); buffer.clear(); //clear后position和limit的变化 System.out.println("clear后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity()); } }
运行结果:
存入元素后position和limit的变化==>position:0 limit:15 capacity:15 存入元素后position和limit的变化==>position:10 limit:15 capacity:15 flip后position和limit的变化==>position:0 limit:10 capacity:15 0 1 2 3 4 读取Buffer元素后position和limit的变化==>position:5 limit:10 capacity:15 rewind==>position:0 limit:10 capacity:15 第二次flip后position和limit的变化==>position:0 limit:0 capacity:15 clear后position和limit的变化==>position:0 limit:15 capacity:15
结果分析:
1).当第一次创建Buffer对象时
position = 0, capacity = limit = Buffer数组容量大小
2).往Buffer添加数据
position = 数组所占数据的大小,capacity = limit = Buffer数组容量大小
3).buffer.flip()操作
position = 0, limit = 数组中所占元素的大小,即原position值, capacity = Buffer数组容量大小
4).buffer.get()获取元素
position = 获取元素的个数,limit = 数组中所占元素的大小,capacity = Buffer数组容量大小
5).再次buffer.flip()
position = 获取元素的个数,limit = position值, capacity = Buffer数组容量大小 注: 当执行flip操作,limit值总是等于上一次的position值
6).buffer.clear
position = 0, capacity = limit = Buffer数组容量大小
总结:
i. put(): position = 数组元素个数 , limit 和 capacity 不变 ii. flip(): position = 0, limit = 原position值, capacity 不变 iii. rewind(): position = 0, limit 和 capacity 不变 iiii. claer(): 回到初始状态,position = 0, capacity = limit = Buffer数组容量大 小。