NIO

Java nio(new io)是从Java1.4版本开始引入的一个新的io api,可以替代标准的Java IO API。NIO与原来IO有同样的作用和目的。

  • 面向缓存区(Buffer)
  • 基于IO通道(Channel)
  • 支持同步和异步
  • 更高效读写

    NIO和IO的主要区别

    | IO | NIO | | :—-: | :—-: | | 面向流 | 面向缓存区 | | 同步IO | 同步IO/异步IO | | | 选择器(Selectors) |

Buffer的常用方法

方法 描述
Buffer clear() 清空缓冲区并返回对缓冲区的引用
Buffer flip() 将缓冲区的界限设置为当前位置,并将当前位置充值为 0
int capacity() 返回 Buffer 的 capacity 大小
boolean hasRemaining() 判断缓冲区中是否还有元素
int limit() 返回 Buffer 的界限(limit) 的位置
Buffer limit(int n) 将设置缓冲区界限为 n, 并返回一个具有新 limit 的缓冲区对象
Buffer mark() 对缓冲区设置标记
int position() 返回缓冲区的当前位置 position
Buffer position(int n) 将设置缓冲区的当前位置为 n , 并返回修改后的 Buffer 对象
int remaining() 返回 position 和 limit 之间的元素个数
Buffer reset() 将位置 position 转到以前设置的 mark 所在的位置
Buffer rewind() 将位置设为为 0, 取消设置的 mark

直接与非直接缓冲区

非直接缓存区

nio - 图1

直接缓存区

nio - 图2

通道(Channel)

Java 为Channel接口提供的最主要实现类如下:

  • FileChannel:用于读取、写入、映射和操作文件的通道。
  • DatagramChannel:通过UDP读写网络中的数据通道。
  • SocketChannel:通过TCP读写网络中的数据。
  • ServerSocketChannel:可以监听新进来的TCP连接,对每一个新进来 的连接都会创建一个SocketChannel。

获取通道:

  • FileInputStream.getChannel()
  • FileOutputStream.getChannel()
  • RandomAccessFile.getChannel()
  • DatagramSocket.getChannel()
  • Socket.getChannel()
  • ServerSocket.getChannel()
  • XXXChannel.open()

transferFrom()和transferTo()

将数据从源通道传输到其他 Channel 中,该方法操控直接内存

选择器(Selector)

选择器(Selector)是SelectableChannle对象的多路复用器,Selector可以同时监控多个SelectableChannel的IO状况,也就是说,利用Selector可使一个单独的线程管理多个Channel。Selector是非阻塞IO的核心。

方法 描述
Set keys() 所有的SelectionKey集合。代表注册在该Selector上的Channel
selectedKeys() 被选择的SelectionKey集合。返回此Selector的已选择键集
int select() 监控所有注册的Channel,当它们中间有需要处理的IO操作时,该方法返回,并将对应得的SelectionKey加入被选择的SelectionKey 集合中,该方法返回这些Channel的数量。
int select(long timeout) 可以设置超时时长的select()操作
int selectNow() 执行一个立即返回的select()操作,该方法不会阻塞线程
Selector wakeup() 使一个还未返回的select()方法立即返回
void close() 关闭该选择器

SelectionKey

表示 SelectableChannel 和Selector之间的注册关系。每次向 选择器注册通道时就会选择一个事件(选择键)。选择键包含两个表示为整 数值的操作集。操作集的每一位都表示该键的通道所支持的一类可选择操 作。

方法 描述
int interestOps() 获取感兴趣事件集合
int readyOps() 获取通道已经准备就绪的操作的集合
SelectableChannel channel() 获取注册通道
Selector selector() 返回选择器
boolean isReadable() 检测Channal中读事件是否就绪
boolean isWritable() 检测Channal中写事件是否就绪
boolean isConnectable() 检测Channel中连接是否就绪
boolean isAcceptable() 检测Channel中接收是否就绪

代码

  1. public class NioSocket {
  2. @Test
  3. public void sent() {
  4. try (SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9098))) {
  5. sc.configureBlocking(false);
  6. ByteBuffer buffer = ByteBuffer.allocate(1024);
  7. Scanner scanner = new Scanner(System.in);
  8. while (scanner.hasNext()) {
  9. String s = scanner.next();
  10. buffer.put(s.getBytes());
  11. buffer.flip();
  12. sc.write(buffer);
  13. buffer.clear();
  14. }
  15. } catch (IOException ignored) {
  16. }
  17. }
  18. @Test
  19. public void accept() {
  20. try (ServerSocketChannel sc = ServerSocketChannel.open()) {
  21. sc.bind(new InetSocketAddress(9098));
  22. sc.configureBlocking(false);
  23. ByteBuffer buffer = ByteBuffer.allocate(1024);
  24. Selector selector = Selector.open();
  25. sc.register(selector, SelectionKey.OP_ACCEPT);
  26. while (selector.select() > 0) {
  27. Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
  28. while (iterator.hasNext()) {
  29. SelectionKey selectionKey = iterator.next();
  30. if (selectionKey.isAcceptable()) {
  31. SocketChannel socket = sc.accept();
  32. socket.configureBlocking(false);
  33. socket.register(selector, SelectionKey.OP_READ);
  34. } else if (selectionKey.isReadable()) {
  35. SocketChannel socket = (SocketChannel) selectionKey.channel();
  36. while (socket.read(buffer) > 0) {
  37. buffer.flip();
  38. System.out.println(new String(buffer.array(),0,buffer.limit()));
  39. buffer.clear();
  40. }
  41. }
  42. iterator.remove();
  43. }
  44. }
  45. } catch (IOException ignored) {
  46. }
  47. }
  48. }

OpenOption实现类

StandardOpenOption 解释
READ 以读取方式打开文件
WRITE 已写入方式打开文件
CREATE 如果文件不存在,创建
CREATE_NEW 如果文件不存在,创建;若存在,异常
APPEND 在文件的尾部追加
DELETE_ON_CLOSE 当流关闭的时候删除文件
TRUNCATE_EXISTING 把文件设置为0字节
SPARSE 文件不够时创建新的文件
SYNC 同步文件的内容和元数据信息随着底层存储设备
DSYNC 同步文件的内容随着底层存储设备