什么是ByteBuffer?
Netty是通过Channel接收和发送数据的,Channel中的数据即为ByteBuffer(缓冲区),同时采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。
ByteBuffer重要的属性:
capacity:
作为一个内存块,Buffer有固定的大小值,也叫作“capacity”,只能往其中写入capacity个byte、long、char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清楚数据)才能继续写数据。
position:
当你写数据到Buffer中时,position表示当前的位置。出事的position值为0,当写入一个字节数据到Buffer中后,position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity-1。当读取数据时,也是从某个特定位置读,讲Buffer从写模式切换到读模式,position会被重置为0。当从Buffer的position处读取一个字节数据后,position向前移动到下一个可读的位置。
limit:
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)
代码演示:
public static void main(String[] args) throws IOException {
RandomAccessFile ram = new RandomAccessFile("E:\\aaa.txt", "r");
FileChannel fileChannel = ram.getChannel();//FileChannel是处理文件的channel 相比IO 这个比较简单
ByteBuffer rendBuffer = ByteBuffer.allocate(1024);//ByteBuffer 刚被创建的时候 position为 0 limit就是 capacity
bufferPosition("初始化ByteBuffer的时候",rendBuffer);
int characters = fileChannel.read(rendBuffer);//将channel中的数据读到buffer的时候 position 就是文件的字符数 limit 仍然是capacity
bufferPosition("从chanel中读到buffer的时候",rendBuffer);
//全部读完之后 limit position capacity的位置
if (characters > 0) {
rendBuffer.flip();//调用了一次flip后 position为0 limit为之前position的位置
bufferPosition("flip之后",rendBuffer);
byte[] bytes = new byte[rendBuffer.remaining()];
rendBuffer.get(bytes);//读完之后 此时的position 和limit相等
}
private static void bufferPosition(String desc,ByteBuffer rendBuffer) {
System.out.println(desc+": "+"指针现在的位置position :"+rendBuffer.position()+"容量capacity
"+rendBuffer.capacity()+" limit"+rendBuffer.limit());
}
}
因为ByteBuffer中的数据是一个连续的byte类型数组,所以我们也可以一个个的读取,可以发现position的值一直在改变
rendBuffer.flip(); //flip()方法是让position=0,limit=position,mark=-1
while (rendBuffer.hasRemaining()){
byte b = rendBuffer.get();
System.out.println((char)b);
bufferPosition("一个一个读的时候",rendBuffer);
}
ByteBuffer常用的API
rewind()
rewind()方法:Buffer.rewind()方法将position设置为0,使得可以重读Buffer中的所有数据,limit保持不变。(ByBuffer中的数据不是读完就没了,可以重复读哦)
clear()和capacity()
clear方法:position将被设置为0,limit设置为capacity的值。
compact()方法:将所有未读的数据拷贝到Buffer起始处,然后将position设置到最后一个未读元素的后面,limit属性依然设置为capacity。可以使得Buffer中的未读数据还可以在后续中被使用。
compact()方法代码演示
rendBuffer.flip();
//数据不读完调用compact()时
for(int i=0;i<5;i++){
byte b = rendBuffer.get();
System.out.println((char)b);
}
bufferPosition("一次没有读完之后",rendBuffer);
rendBuffer.compact();// 将position的值为 limit-(当前的)position
// limit设置成capactiy 可以使得Buffer中的未读数据还可以在后续中被使用。(可以理解为将之前没有读完的数据又重新写了一遍)
bufferPosition("调用了compact之后",rendBuffer);
rendBuffer.flip();//这个时候再读的话 limit的就是剩下的数量 position=0 limit=position (注意这个如果不调用flip()方法时,就会出现从position为limit的位置开始读,所以一旦决定要读数据就要flip()没错的)
bufferPosition("compact之后再flip",rendBuffer);
while (rendBuffer.hasRemaining()){
byte b = rendBuffer.get();
System.out.println((char)b);
}
网友评论