NIO
Contents
Demo 源码:
https://github.com/huangzhenshi/IO_NIO_NIO2Dem
总结
- NIO 分为NIO 和NIO2 ,NIO2是JDK1.7的新特性,NIO1是 1.4的新特性,做了操作简化
- IO 和NIO最大的区别在于阻塞和非阻塞,这在socket编程聊天室时区别很大。IO每个连接都需要一个线程挂起去处理一次IO请求,一直到作业完成。而NIO则通过轮询的方式异步去处理每个channel。
参考blog:
http://ifeve.com/selectors/
https://www.cnblogs.com/wnlja/p/4368127.html
Channel(对缓冲区进行双向操作)
- FileChannel (字节channel,只有阻塞的)
- DatagramChannel (UDP 交互)
- SocketChannel (TCP 交互)
- ServerSocketChannel (TCP 服务端,监听新进来的TCP连接)
Buffer
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存
Buffer的基本用法
- 写入数据到Buffer,read(buf)
- 调用flip()方法
- 从Buffer中读取数据,buf.get()
- 调用clear()方法或者compact()方法,清空缓存区
|
关键字:
- capacity:缓冲池的大小
- position:初始值为0
- 写
当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity –1 - 读
当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。
- limit:读模式下,表示之前写的position位置,写时就是capacity
- flip()方法:将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。
Selector
http://ifeve.com/selectors/
能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件,仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道
- Selector selector = Selector.open();//创建
- SelectionKey key = channel.register(selector,Selectionkey.OP_READ);
第二个参数表示channel开放什么事件给selector:Connect、Accept、Read、Write
|
SelectionKey
|
以上代码看出来,一个key管理映射到:
- channel
- selector
- interest集合 (监听的事件类型)
- ready集合 (监听已出发事件集合)
- attachment (读写交互buffer).
|
文本复制的两种方式
利用函数transferFrom复制文本
public static void NIOCopyFile() throws Exception{RandomAccessFile fromFile = new RandomAccessFile(fileFrom, "rw");FileChannel fromChannel = fromFile.getChannel();RandomAccessFile toFile = new RandomAccessFile(fileTo, "rw");FileChannel toChannel = toFile.getChannel();long position = 0;long count = fromChannel.size();toChannel.transferFrom(fromChannel, position, count);}通过常规的Channel、Buffer进行文本的复制,2个Channel对一个ByteBuffer进行操作
public static void copyFileNioOrigin() throws Exception{RandomAccessFile aFile = new RandomAccessFile(fileFrom, "rw");RandomAccessFile toFile = new RandomAccessFile(fileTo, "rw");FileChannel inChannel = aFile.getChannel();FileChannel toChannel = toFile.getChannel();ByteBuffer buf = ByteBuffer.allocate(1024);while (inChannel.read(buf) != -1) {buf.flip();toChannel.write(buf);buf.clear();}aFile.close();toFile.close();}