关于NIO

来自Wikioe
Eijux讨论 | 贡献2021年1月3日 (日) 05:51的版本 →‎NIO 组件
跳到导航 跳到搜索


关于

Java NIO,即“New I/O”(另一说“No-Blocking I/O”):采用内存映射文件的方式来处理输入输出:NIO将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样访问文件了。

与 IO

NIO与标准IO不同:NIO支持面向缓冲区的、基于通道的IO操作,以更加高效的方式进行文件的读写操作。

  • (“旧”的I/O包已经使用NIO重新实现过,“即使我们不显式的使用NIO编程,也能从中受益”)
  • (NIO子系统不会取代java.io包中可用的基于流的I/O类)
IO NIO
面向流(Stream Oritented) 面向缓冲区(Buffer Oritented)
阻塞IO(Blocking IO) 非阻塞IO(None Blocking IO)
选择器(Selecters)

NIO 包

从JDK1.4开始提供的一系列改进的输入/输出处理,这些类都被放在java.nio包及子包下:

Java.nio相关包.png
包名称 使用/目的
java.nio NIO系统的顶级包,NIO系统封装了各种类型的缓冲区。
java.nio.charset 封装了字符集,并且还支持分别将字符转换为字节和字节到编码器和解码器的操作。
java.nio.charset.spi 用于支持字符集服务提供者
java.nio.channels 支持通道,这些通道本质上是打开I/O连接。
java.nio.channels.spi 用于支持频道的服务提供者
java.nio.file 提供对文件的支持
java.nio.file.spi 用于支持文件系统的服务提供者
java.nio.file.attribute 用于提供对文件属性的支持

(为什么学习NIO)

IO操作往往在两个场景下会用到:

  1. 文件I/O
  2. 网络I/O:NIO的优势体现;

【IO:同步、异步,阻塞、非阻塞】

(见IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)

NIO 组件

NIO中的所有I/O都是通过一个通道开始的。数据总是从缓冲区写入通道,并从通道读取到缓冲区:

  1. 从通道读取:创建一个缓冲区,然后请求通道读取数据;
    NIO:数据读取.png
  2. 通道写入:创建一个缓冲区,填充数据,并要求通道写入数据;
    NIO:数据写入.png

Java NIO 由以下几个核心部分组成:

  • Buffer
  • Channel
  • Selector

Channel

通道,是用于在实体和字节缓冲区之间有效传输数据的介质。它从一个实体读取数据,并将其放在缓冲区块中以供消费。 Java NIO Channel 不同于流:

  1. 既可以从通道中读取数据,又可以写数据到通道;但流的读写通常是单向的。
  2. 通道可以异步地读写。
  3. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。


“java.nio.channels”类的层次结构:

Java.nio.channels类的层次结构.png

其中顶层接口:

package java.nio.channels;

import java.io.IOException;
import java.io.Closeable;

public interface Channel extends Closeable {
    // 检查通道是否打开
    public boolean isOpen();
    // 关闭通道
    public void close() throws IOException;

}

Java NIO中,主要使用的通道如下:

  1. FileChannel”:从文件中读写数据;
  2. DatagramChannel”:通过UDP读写网络中的数据;
  3. SocketChannel”:通过TCP读写网络中的数据;
  4. ServerSocketChannel”:监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel;


示例:

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

Selector

Scatter / Gather

分散(scatter) 聚集(gather)

Channel to Channel Transfers

常用Channel

FileChannel DatagramChannel SocketChannel ServerSocketChannel


Java NIO非阻塞式服务器

其他

Pipe Path Files AsynchronousFileChannel