一文看懂Java NIO

Java NIO 英文参考文档

简介

Java Non-blocking IO
JAVA NIO是非阻塞的.线程从channel读取数据到buffer的同时线程可以做其他操作。当数据完全读入到buffer后,线程可以继续对数据进行操作。

在标准的IO API中使用字节流和字符流来进行IO操作。
在NIO中使用Channels和Buffers来进行IO操作。
数据通过channel读入buffer,也可以从buffer写入channel

channels

channel实现了 UTP TCP Server IO

  • FileChannel 基于文件读写
  • DatagramChannel 基于UDP读写
  • SocketChannel 基于TCP读写
  • ServerSocketChannel 监听TCP链接,对于每一个链接都建立SocketChannel

demo

    RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
    FileChannel inChannel = aFile.getChannel();
    ByteBuffer buf = ByteBuffer.allocate(48);

    int bytesRead = inChannel.read(buf);
    while (bytesRead != -1) {

      System.out.println("Read " + bytesRead);
      buf.flip();

      while(buf.hasRemaining()){
          System.out.print((char) buf.get());
      }

      buf.clear();
      bytesRead = inChannel.read(buf);
    }
    aFile.close();

Buffer

Buffer的本质是一个可读写的内存块,Buffer对象里包含了可读写的内存块,以及一系列操作。

Buffer中的三个重要属性

  • capacity 大小可调的数据存储容器 ,有容量上限,到达上线后不能继续加入数据,只能读取或清空。
  • position 读模式时 从此处开始读取数据,写模式时 从此处开始写入数据
  • limit 读模式时 此处为最后一个数据的位置,写模式时 此处为capacity容量上限处
    在这里插入图片描述

Buffer 类型

以下列出了不通种类的Buffer:ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer,MappedByteBuffer。

Buffer 创建

调用静态方法allocate()来创建分配空间 创建buffer对象

ByteBuffer buf = ByteBuffer.allocate(48);

读写入buffer

  • 使用channel写入数据
int bytesRead = inChannel.read(buf);
  • 使用buffer自带方法写入数据
buffer.put("写入的数据")
  • 使用channel读入数据
int bytesWritten = inChannel.write(buf);
  • 使用get函数读数据
byte aByte = buf.get(); 

Buffer 使用四个步骤

  1. 把数据写入Buffer
  2. 调用buffer.flip() ,从写入模式转成读取模式
  3. 可以读取Buffer中所有的数据
  4. 调用 buffer.clear() 清空数据 或 buffer.compact 清除已读数据

Buffer 常用函数

  • flip() 切换读写模式
  • rewind() 设置position为0,limit不改变
  • clear() 清空buffer所有数据都不能在读。此方法使position=0、limit=capacity
  • compact() 清空已读数据,复制未读数据作为capacity的头。此方法使position=未读处最后、limit=capacity,此时buffer处于写入模式
  • mark() 记录当前的位置(position)
  • reset() 回到标记位置
  • equals() 两个buffer相等条件:相同的数据类型、空间大小相等、空间内容一样
  • compareTo() 此方法比较buffer内数据大小,两个buffer必须类型相同

demo:

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

//create buffer with capacity of 48 bytes
ByteBuffer buf = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buf); //read into buffer.
while (bytesRead != -1) {

  buf.flip();  //make buffer ready for read

  while(buf.hasRemaining()){
      System.out.print((char) buf.get()); // read 1 byte at a time
  }

  buf.clear(); //make buffer ready for writing
  bytesRead = inChannel.read(buf);
}
aFile.close();

Scatter & Gather

scater 和 gather 是channels读取的两个概念。
Scatter 从channel中读分片取值,以下是从一个包含header和body的channel中读取的例子

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);

ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);

Gather channel读入多个Buffer

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);

//write data into buffers

ByteBuffer[] bufferArray = { header, body };
channel.write(bufferArray);

Selectors

Selectors 是一个管理工具,可以管理多个channel对操作。
由此一个线程可以操作多个channel。

猜你喜欢

转载自blog.csdn.net/Jone__/article/details/83547652