NIO的Buffer

NIO的Buffer教程

Java 中 Buffer 用于和 Java NIO 中的 Channel 进行交换。它是缓冲区,无论数据的写入或者数据的读取,都会操作缓冲区。Buffer 本质就是一个数组,它在里面封装了一些方法,用来比较方便的操作对应的数组。

Buffer描述

我们之前的文章中介绍过,Java 的基本类型都有对应的 Buffer,除了 Boolean 类型。它里面有一些比较重要的属性:capacity、position 和 limit。根据字面的意思,我们可以理解为 capacity 表示 Buffer 的容量,position 表示位置 ,limit 表示容量大小。其中 position 和 limit 的含义取决于 Buffer 处于读的模式还是写的模式。

01 Buffer 结构图.png

capacity

作为一个内存块,Buffer有一个固定的大小值,叫 capacity。你只能往里写 capacity 个 byte、long,char 等类型。一旦 Buffer 满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

poisition

指定下一个被操作的元素的索引。当你写数据到 Buffer 中时,position 表示当前的位置。初始的 position 值为 0。当一个 byte、long 等数据写到 Buffer 后, position 会向前移动到下一个可插入数据的 Buffer 单元。position 最大可为capacity – 1。
当读取数据时,也是从某个特定位置读。当将 Buffer 从写模式切换到读模式,position 会被重置为 0。当从 Buffer 的 position 处读取数据时,position 向前移动到下一个可读的位置。

limit

在写模式下,Buffer 的 limit 表示你最多能往 Buffer 里写多少数据。limit 等于 Buffer 的 capacity。
在读模式下, limit 表示你最多能读到多少数据。因此,当切换 Buffer 到读模式时,limit 会被设置成写模式下的 position值。换句话说,你能读到之前写入的所有数据(limit 被设置成已写数据的数量,这个值在写模式下就是 position)。

Buffer继承关系

在 NIO 中,所有的缓冲区都继承了 Buffer。最常用的就是 ByteBuffer,对于 Java 中的基本类型,它都有一个具体的 Buffer 类型与之对应,除了 Boolean 类型。它们的对应关系如下图:

02 Buffer 子类.png

Buffer下的方法

flip()

flip 方法将 Buffer 从写模式切换到读模式。调用 flip() 方法会将 position 设回 0,并将 limit 设置成之前 position 的值。

rewind()

Buffer.rewind() 将 position 设回 0,所以你可以重读 Buffer 中的所有数据。limit 保持不变,仍然表示能从 Buffer 中读取多少个元素(byte、char等)。

clear()与compact()方法

一旦读完 Buffer 中的数据,需要让 Buffer 准备好再次被写入。可以通过 clear() 或 compact() 方法来完成。
clear:position 将被设回 0,limit 被设置成 capacity 的值。换句话说,Buffer 被清空了。Buffer 中的数据并未清除,只是这些标记告诉我们可以从哪里开始往 Buffer 里写数据。如果 Buffer 中有一些未读的数据,调用 clear() 方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。
compact:将所有未读的数据拷贝到 Buffer 起始处。然后将 position 设到最后一个未读元素正后面。limit 属性依然像 clear() 方法一样,设置成 capacity。现在 Buffer 准备好写数据了,但是不会覆盖未读的数据。

mark()与reset()方法

通过调用 Buffer.mark() 方法,可以标记 Buffer 中的一个特定 position。之后可以通过调用 Buffer.reset() 方法恢复到这个position。

equals()与compareTo()方法

可以使用 equals() 和 compareTo() 方法两个 Buffer。

queals 比较的是两个 buffer 的 类型,剩余数据数量和剩余的数据元素是否相同。

compareTo() 方法比较两个Buffer的剩余元素(byte、char等)。

Buffer总结

Buffer 其实就是一个特殊的数组,它里面封装了一些方法,使用户对这些数组操作更加方便,更加简单。NIO 是针对缓冲区进行操作的,所以所有的读写操作都会经过缓冲区,都是对缓冲区进行操作。