正文
public int read(ByteBuffer dst) throws IOException;
public int write(ByteBuffer src) throws IOException;
从上面的接口我们可以看到Channel和ByteBuffer之间发生的两个基本行为,即readding/writing。无论是对文件(FileChannel)还是对网络(SocketChannel)的读写,他们都会去实现这两个基本行为。好了,我们已经从总体上认识ByteBuffer在JAVA NIO所处的位置和担当的角色了,下面我们继续深入一点认识ByteBuffer。
ByteBuffer有四个重要的属性,分别为:mark、position、limit、capacity,和两个重要方法分别为:flip和clear。ByteBuffer的底层存储结构对于堆内存和直接内存分别表现为堆上的一个byte[]对象和直接内存上分配的一块内存区域。既然是一块内存区域,那么我们就可以对其进行基于字节的读和写,而ByteBuffer的四个int类型的属性则是指向这块区域的指针:
-
position:读写指针,代表当前读或写操作的位置,这个值总是小于等于limit的。
-
mark:在使用ByteBuffer的过程中,如果想要记住当前的position,则会将当前的position值给mark,让需要恢复的时候,再将mark的值给position。
-
capacity:代表这块内存区域的大小。
-
limit:初始的Buffer中,limit和capacity的值是相等的,通常在clear操作和flip操作的时候会对这个值进行操作,在clear操作的时候会将这个值和capacity的值设置为相等,当flip的时候会将当前的position的值给limit,我们可以总结在写的时候,limit的值代表最大的可写位置,在读的时候,limit的值代表最大的可读位置。clear是为了写作准备、flip是为了读做准备。
ByteBuffer指针示意图
在JAVA NIO中,原生的ByteByffer家族成员很简单,主要是HeapByteBuffer、DirectByteBuffer和MappedByteBuffer:
-
HeapByteBuffer是基于堆上字节数组为存储结构的缓冲区。
-
DirectByteBuffer是基于直接内存上的内存区域为存储结构的缓冲区。
-
MappedByteBuffer主要是文件操作相关的,它提供了一种基于虚拟内存映射的机制,使得我们可以像操作文件一样来操作文件,而不需要每次将内容更新到文件之中,同时读写效率非常高。
Netty之ByteBuf
相比于ByteBuffer的读写指针position,ByteBuf提供了两个指针readerIndex和writeIndex来分别指向读的位置和写的位置,不需要每次为读写做准备,直接设置读写指针进行读写操作即可。我们看看处于中间状态的状态: