NIO之Channel通道(一)-Channel、FileChannel

2022-04-25 14:20:24 浏览数 (1)

NIO之Channel通道(一)-Channel、FileChannel

Channel叫做通道,用于I/O操作的连接。与Stream不同,可以双向的进行数据通信。

Channel相关的的类和接口都存放于以下两个包中:

  • java.nio.channels:定义了各种通道,这些通道表示到能够执行 I/O 操作的实体(如文件和套接字)的连接;定义了用于多路复用的、非阻塞 I/O 操作的选择器。
  • java.nio.channels.spi:用于 java.nio.channels 包的服务提供程序类。

1 获取通道的方式

获取通道有以下6种方式。

1.1 getChannel()

Java针对支持通道的类提供了getChannel()方法:

  • 本地IO:FileInputstream、FileOutputstream、RandomAccessFile。
  • 网络IO:Socket、ServerSocket、DatagramSockte。

1.2 open()

在JDK1.7中的NIO.2针对各个通道提供了静态方法open()

1.3 newByteChannel()

在JKD1.7中的NIO.2的Files工具类的newByteChannel()

1.4 数据传输

通道之间的数据传输:

  • transferFrom()
  • transferTo()

1.5 分散与聚集

分散(Scatter)与聚集(Gather):

  • 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区。
  • 聚集写入(Gathering Writes):将多个缓冲区的数据聚集到通道中。

1.6 字符集

字符集:Charset

  • 编码:字符串→字符数组
  • 解码:字符数组→字符串

2 Channel

Channel是一个接口,以下为其实现类和子类继承结构。

代码语言:javascript复制
Channel
	|-AbstractInterruptibleChannel
	|	|- FileChannel
	|	|- FileChannelImpl
	|- ReadableByteChannelImpl
	|	|- SelectableChannel
	|		|- AbstractSelectableChannel
	|				|- ServerSocketChannel
	|				|- SocketChannel
	|				|- DatagramChannel

2.1 重要方法

此接口只有两个方法,分别如下:

2.1.1 close()

关闭此通道。

2.1.2 isOpen()

判断此通道是否处于打开状态。

3 FileChannel

主要用于文件的读写,可以从磁盘上读取文件,也可以向磁盘上写入文件。

这是一个抽象类,此类继承AbstractInterruptibleChannel,实现了SeekableByteChannel、GatheringByteChannel、ScatteringByteChannel三个接口。

创建FileChannel对象,底层调用的是FileChannelImpl的构造函数。

3.1 RandomAccessFile模式

RandomAccessFile的模式有四种:r、rw、rws、rwd。

  • r:只能读。
  • rw:可读,可写。
  • rws:可读可写,每次改动都强制保存,在写入的时候会将操作系统对该文件的元数据也一起刷盘,体现就是文件的更新时间会修改。
  • rwd:可读,可写,每次改动都强制保存。

3.2 重要方法

3.2.1 open()

此方法通过文件系统创建一个FileChannel。

此方法有两个重载如下:

  • open(Path, Set<? extends OpenOption>, FileAttribute<?>...)
  • open(Path, OpenOption...)
3.2.2 read()

读取缓冲区中的内容,重载的方法大部分都是抽象方法,等待子类进行实现。

重载方法如下:

  • read(ByteBuffer)
  • read(ByteBuffer, long)
  • read(ByteBuffer[], int, int)
  • read(ByteBuffer[])
3.2.3 write()

将缓冲区中的内容写出,重载的方法大部分都是抽象方法,等待子类进行实现。

重载方法如下:

  • write(ByteBuffer)
  • write(ByteBuffer, long)
  • write(ByteBuffer[], int, int)
  • write(ByteBuffer[])
3.2.4 position()

返回这个通道中文件的当前位置。

3.2.5 position(long)

设置一个通道中文件的当前位置。

3.2.6 size()

返回当前通道中,文件的大小。

3.2.7 truncate(long)

将此通道中的文件截断为指定的大小。

3.2.8 force(boolean)

将通道内的更新内容强制写入存储设备中。

3.2.9 transferTo(long, long, WritableByteChannel)

将文件中的内容传送到写通道中。

3.2.10 transferFrom(ReadableByteChannel, long, long)

将通道中的内容传送到读通道中。

3.2.11 lock()

获取此通道给定的锁。有两个重载的方法。

  • lock(long, long, boolean)
  • lock()
3.2.12 tryLock()

尝试获取此通道给定的锁,有两个重载方法。

  • tryLock(long, long, boolean)
  • tryLock()

3.3 案例

代码语言:javascript复制
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;

	public static void fctest(String file, String mod) throws Exception {
		// 打开文件
		RandomAccessFile raf = new RandomAccessFile(file, mod);
		// 获取一个通道
		FileChannel fc = raf.getChannel();
		// 创建缓冲区
		ByteBuffer buffer = ByteBuffer.allocate(16);
		// 存入缓冲区数据
		buffer.put("FileChannelTest".getBytes(StandardCharsets.UTF_8));
		// 将缓冲区切换成读模式
		buffer.flip();
		// 将缓冲区中的数据通过通道写出
		fc.write(buffer);
		// 清空缓冲区
		buffer.clear();
		// 读取缓冲区数据
		fc.read(buffer);
		fc.close();
		raf.close();
	}

0 人点赞