NIO
来源:互联网 发布:魔乐科技java笔记 编辑:程序博客网 时间:2024/06/04 18:18
传统的IO流都是都是阻塞式的输入、输出。比如在读取输入流中的数据时,如果没有读取到有效数据,程序将会在此处阻塞该线程的执行。
并且传统的IO流都是通过字节的移动来处理的(即使不直接去处理字节流,但底层的实现还是依赖于字节处理),也就是说,面向流的输入/输出系统一次只能处理一个字节,因此面向流的输入输出的效率不高。
从JDK1.4开始,Java提供了一系列改进的输入/输出处理的新功能,这些功能被统称为新IO(New IO,简称NIO)。
NIO它既可以说成“新I/O”,也可以说成非阻塞式I/O。下面是java NIO的工作原理:
1. 由一个专门的线程来处理所有的 IO 事件,并负责分发。
2. 事件驱动机制:事件到的时候触发,而不是同步的去监视事件。
3. 线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换。
NIO(New IO,简称NIO),使用内存映射文件的方式来处理输入/输出,将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了(这种方式模拟了操作系统上的虚拟内存的概念)。通过这种方式来进行输入/输出比传统的输入/输出要快得多。
在NIO中,所有数据都需要通过通道Channel传输。它提供了一个map()方法,通过该方法可以直接将“一块数据”映射到内存中,是面向块的处理。
发送到Channel中的所有对象都必须首先放到Buffer中,而从Channel中读取的数据也必须先放到Buffer中。Buffer可以被理解为一个容器,它的本质是一个数组。Buffer是一个抽象类,它的常用子类是ByteBuffer,它可以在底层字节数组上进行get/set操作。其他子类比如CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。
Channel
Channel与传统的流的区别:
(1) Channel可以直接将指定文件的部分或全部直接映射成Buffer
(2) 程序不能直接访问Channel中的数据,包括读写,Channel只能和Buffer进行交互。
也就是说,如果要从Channel中取得数据,必须先用Buffer从Channel中取出一些数据,然后让程序从Buffer中取出这些数据;
如果要将程序中的数据写入Channel,先让程序将数据放入Buffer中,程序再将Buffer里的数据写入Channel中
Channel接口的实现类有:
DatagramChannel、FileChannel、Pipe.SinkChannel、Pipe.SourceChannel、SelectableChannel、ServerSocketChannel、ServerSocketChannel、SocketChannel等
所有的 Channel都不可以直接通过构造器来创建,而是通过传统的节点 InputStream、OutputStream 的 getChannel()方法来返回对应的Channel,不同的节点流对象获得的CHannel不一样。比如FileInputStream的 getChannel()返回的是FileChannel,PipedInputStream的getChannel()返回的是Pipe.SinkChannel、Pipe.SourceChannel。
Channel中常用的三类方法:
(1)public abstract MappedByteBuffer map(FileChannel.MapMode mode,long position,long size):将Channel对应的部分或
全部数据映射成ByteBuffer。
第一个参数:只读(MapMode.READ_ONLY) 、读/写(MapMode.READ_WRITE) 等模式。
(2)read():从Buffer中读取数据
(3)write():向Buffer中写数据
Buffer
Buffer中三个重要的概念:
(1) 容量 (capacity):缓冲区的容量capacity表示该Buffer的最大数据容量,即最多可以存储多少数据。capacity不可能为负值,创建后不能被改变。
(2) 界限 (limit):第一个不应该被读出或者写入的缓冲区位置索引。也就是说位于limit后面的数据即不可被读,也不可被写。
(3) 位置 (position):用于指明下一个可以被读出的或者写入的缓冲区位置索引。当使用Buffer从Channel中读取数据时,position的值恰好等于已经读到了多少数据。当刚刚新建一个Buffer对象时,其position为0;如果从Channel中读取了2个数据到该Buffer中,则position为2,指向Buffer中第3个位置(索引从0开始)。
Buffer的作用就是装入数据,然后输出数据:
(1) 装入数据。开始时的Buffer的position为0,limit为capacity,程序可以通过put()方法向Buffer中放入一些数据(或从Channel中获取一些数据),每放入一些数据,Buffer的position相应地向后移动一些位置。
(2) 装入数据结束后,调用Buffer的flip()方法,该方法将limit设置为position的位置,将position设为0,这就使Buffer的读写指针又移到了开始位置。该方法调用之后,Buffer为输出数据做好准备。
(3) 输出数据。使用Buffer的get()方法取出数据。
(4) 输出数据结束后,Buffer调用clear()方法,clear()方法不是清空数据,而是将position置为0,将limit置为capacity,再次为Buffer装入数据做准备。
当使用get()和put()方法访问Buffer中的数据时,分为绝对和相对两种:
(1) 相对 (Relative):从Buffer的当前position处开始读取或写入,然后将位置(position)的值按处理元素的个数增加
(2) 绝对 (Absolute):直接根据索引向Buffer中读取或写入数据,使用绝对方式访问Buffer里的数据时,并不会影响位置(position)的值
public class BufferTest { public static void main(String[] args) throws IOException { // 创建Buffer CharBuffer charBuffer = CharBuffer.allocate(8); System.out.println("刚创建Buffer之后的position、limit、capacity分别为:" + charBuffer.position() + " "+ charBuffer.limit()+ " " + charBuffer.capacity()); System.out.println(); // 放入数据 charBuffer.put('i'); charBuffer.put('y'); System.out.println("放入2个数据"); System.out.println("放入数据后的position、limit、capacity分别为:" + charBuffer.position() + " " + charBuffer.limit() + " " + charBuffer.capacity()); System.out.println(); // 调用flip()方法(调用完这个方法之后,就为输出数据做准备,position置为0,limit置为position所在的位置) charBuffer.flip(); System.out.println("调用flip()方法,为读数据做准备。读的范围应该是所写入数据的范围0-position,因此把limit置为position,再把position置为0"); System.out.println("调用flip()方法之后的position、limit、capacity分别为:" + charBuffer.position() + " " + charBuffer.limit() + " " + charBuffer.capacity()); System.out.println(); // 相对:取出元素,position的值会改变 System.out.println("以相对Relative的方式取值"); System.out.println("取出第一个元素(position=0):" + charBuffer.get()); System.out.println("取出第一个元素之后position变成了:" + charBuffer.position()); System.out.println(); // 调用clear()方法 charBuffer.clear(); System.out.println("调用clear方法,为装入数据做准备,因此position置为0,limit置为capacity"); System.out.println("调用clear()方法之后的position、limit、capacity分别为:" + charBuffer.position() + " " + charBuffer.limit() + " " + charBuffer.capacity()); System.out.println("执行clear()方法之后,缓冲区的内容并没有被清除,第一个元素为:" + charBuffer.get(1)); System.out.println(); // 放入数据 System.out.println("重新放入两个字符数据"); charBuffer.put('n'); charBuffer.put('m'); System.out.println("放入数据后的position、limit、capacity分别为:" + charBuffer.position() + " " + charBuffer.limit() + " " + charBuffer.capacity()); System.out.println(); charBuffer.flip(); System.out.println("根据索引取数据,第二个数据为:" + charBuffer.get(1)); System.out.println("根据position取数据:" + charBuffer.get()); }}
控制台输出:
刚创建Buffer之后的position、limit、capacity分别为:0 8 8放入2个数据放入数据后的position、limit、capacity分别为:2 8 8调用flip()方法,为读数据做准备。读的范围应该是所写入数据的范围0-position,因此把limit置为position,再把position置为0调用flip()方法之后的position、limit、capacity分别为:0 2 8以相对Relative的方式取值取出第一个元素(position=0):i取出第一个元素之后position变成了:1调用clear方法,为装入数据做准备,因此position置为0,limit置为capacity调用clear()方法之后的position、limit、capacity分别为:0 8 8执行clear()方法之后,缓冲区的内容并没有被清除,第一个元素为:y重新放入两个字符数据放入数据后的position、limit、capacity分别为:2 8 8根据索引取数据,第二个数据为:m根据position取数据:n
使用NIO复制文件:
public class NioCopyFileTest { public static void nioCopyFile(String resource,String destination) throws IOException{ //文件输入流 FileInputStream fis = new FileInputStream(resource); //文件输出流 FileOutputStream fos = new FileOutputStream(destination); //读文件通道 FileChannel readChannel = fis.getChannel(); //写文件通道 FileChannel writeChannel = fos.getChannel(); //创建一个容量为1024的ByteBuffer对象 ByteBuffer buffer = ByteBuffer.allocate(1024); while (true) { buffer.clear(); //清空buffer中的内容 int len = readChannel.read(buffer); //读入数据 if(len == -1){ //读取完毕 break; } buffer.flip(); //将写模式转换为读模式。 writeChannel.write(buffer); //写入数据 } fis.close(); fos.close(); } public static void main(String[] args) throws IOException { NioCopyFileTest.nioCopyFile("D:\\temp_buffer.txt", "c:\\temp_buffer.txt"); }}
- nio
- NIO
- NIO
- nio
- NIO
- NIO
- nio
- Nio
- NIO
- NIO
- NIO
- nio
- NIO
- NIO
- NIO
- NIO
- NIO
- NIO
- 每日产品辣评:iPhone 6s全球开卖,没剁手的同学慎刷朋友圈
- 普通平衡车和“最后一公里”之间就差一个igo
- K近邻(KNN)算法(二)---实现约会匹配
- Linux系统中不同用户所使用的$PATH环境变量的区别
- Python编程:从入门到实践的动手试一试答案(第六章)
- NIO
- PuTTY,Xshell,远程连接LInux系统及密钥认证
- 《C与指针》个人笔记
- 数组
- MATLAB常用函数总结
- 安全狗·服云,拿什么驱散云时代的人人自危?
- 到底是谁?拿走了你的钱?
- 智能手机国庆新玩法:不凑热闹不添堵 照样嗨翻天
- 这是一股被低估的力量,将在互联网的下半场爆发