NIO

2020-12-08  本文已影响0人  Edwinpanzzz

Java NIO 简介

Java NIO(New IO)是从 Java 1.4 版本开始引入的一个新的 IO API,可以替代标准的 Java IO API。NIO 与原来的 IO 有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的 IO 操作。NIO 将以更加高效的方式进行文件的读写操作。

Java NIO 与 IO 的主要区别

image.png

通道(Channel)与缓冲区(Buffer)

Java NIO 系统的核心在于:通道(Channel)和缓冲区(Buffer)。通道表示打开到 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO 系统,需要获取用于连接 IO 设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。

举个例子,通道就像铁路,而缓冲区就像火车,铁路本身不能运输数据,火车才可以运输。

缓冲区(Buffer)

一个用于特定基本数据类型的容器。由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类。

Java NIO 中的 Buffer 主要用于与 NIO 通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的。

Buffer 就像一个数组,可以保存多个相同类型的数据。根据数据类型不同(boolean 除外),有以下 Buffer 常用子类:

上述 Buffer 类 他们都采用相似的方法进行管理数据,只是各自管理的数据类型不同而已。都是通过如下方法获取一个 Buffer 对象:

static XxxBuffer allocate(int capacity) : 创建一个容量为 capacity 的 XxxBuffer 对象

缓冲区的基本属性

缓冲区的数据操作

Buffer 所有子类提供了两个用于数据操作的方法:get() 与 put() 方法。

Buffer 的常用方法

image.png

通道(Channel)

由 java.nio.channels 包定义的。Channel 表示 IO 源与目标打开的连接。Channel 类似于传统的“流”。只不过 Channel 本身不能直接访问数据,Channel 只能与 Buffer 进行交互。

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

获取通道

获取通道的一种方式是对支持通道的对象调用 getChannel() 方法。支持通道的类如下:

获取通道的其他方式是使用 Files 类的静态方法 newByteChannel() 获取字节通道。或者通过通道的静态方法 open() 打开并返回指定通道。

通道的数据传输

非直接缓冲区

// 文件的复制
FileInputStream fileInputStream = new FileInputStream("1.jpg");
FileChannel inputStreamChannel = fileInputStream.getChannel();

FileOutputStream fileOutputStream = new FileOutputStream("2.jpg");
FileChannel outputStreamChannel = fileOutputStream.getChannel();

ByteBuffer buffer = ByteBuffer.allocate(1024);
// 将通道数据存入缓冲区
while (inputStreamChannel.read(buffer)!=-1){
        buffer.flip();
        outputStreamChannel.write(buffer);
        buffer.clear();
}

直接缓冲区

// 直接缓冲区
FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
        
// 内存映射文件
MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
        
// 直接对缓冲区进行数据的读写操作
byte[] dst = new byte[inMappedBuf.limit()];
inMappedBuf.get(dst);
outMappedBuf.put(dst);

通道之间的数据传输

FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
        
inChannel.transferTo(0, inChannel.size(), outChannel);
// outChannel.transferFrom(inChannel, 0, inChannel.size());

分散(Scatter)和聚集(Gather)

分散读取(Scattering Reads)是指从 Channel 中读取的数据“分散”到多个 Buffer 中。

image.png

按照缓冲区的顺序,从 Channel 中读取的数据依次将 Buffer 填满。

聚集写入(Gathering Writes)是指将多个 Buffer 中的数据“聚集”到 Channel。

image.png

注意:按照缓冲区的顺序,写入 position 和 limit 之间的数据到 Channel 。

上一篇 下一篇

猜你喜欢

热点阅读