Buffer的基本原理
我们说的缓冲区本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如果我们使用get()
方法从缓冲区获取数据或者使用put()
方法把数据写入缓冲区,都会引起缓冲区状态变化。
在缓冲区中,最重要的属性有下面三个,它们一起合作完成对缓冲区内部的变化跟踪
- position:指定下一个将要写入或者读取的元素索引,它的值由
get()/put()
方法自动更新,在新创建一个Buffer对象时,position被初始化为0 - limit:指定还有多少数据需要取出(在从缓冲区写入通道时),或者还有多少空间可以放入数据(在从通道读入缓冲区时)
- capacity:指定了可以存储在缓冲区中的最大数据容量,实际上,它指定了底层数组的大小,或者至少是指定了准许我们使用的底层数组的容量
这三个属性之间有一些相对大小的关系:0<=position<=limit<=capacity。
举例说明
我们现在需要取读磁盘的一个文件,文件内容如下:
lengwen
我们创建一个新的容量大小为10的ByteBuffer
对象,在初始化时将position设置为0,limit和capacity设置为10,在以后使用ByteBuffer
对象的过程中,capacity的值不在变化,而其他两个将会随着使用而变化。
我们现在要读文件,对于缓冲区来说,是将数据从inputstream
的通道中写到缓冲区, 可以看出我们文件中数据的长度为7,此时往缓冲区写完后position的值为7,即下一个将要被写入的字节索引为7.而limit仍为10
下一步是将数据写入到输出的通道,对于缓冲区来说,就是从缓冲区中读取数据,但在些之前,必须调用flip()
方法。该方法将会完成以下两件事情:(1)把limit设置为当前的position值;(2)把position设置为0
解释:由于position被设置为0,所以可以保证在下一步输出时读取的是缓冲区的第一个字节,而limit被设置为当前的position,可以保证读取的数据正好是之前写入缓冲区的数据
现在调用git()
方法从缓冲区中读取数据写入输出通道,这会导致position的增加而limit保持不变,但position不会超过linit的值,所以在读取之前写入缓冲区的7字节之后,position和limit的值都为7
在从缓冲区读取完成之后,limit的值仍然为7,此时调用clear()
方法能够把所有的状态变化设置为初始化时的值
举例代码
上面说明了使用缓冲区读取文件的全过程,现在去实现一下上述过程
package cn.kevinlu98.netty.buffer;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/**
* Author: 鲁恺文
* Date: 2021/4/29 3:48 下午
* Email: lukaiwen@xiaomi.com
* Description:
*/
public class BufferReadFile {
public static void main(String[] args) throws IOException {
//这里用的是文件I/O处理
FileInputStream fis = new FileInputStream("/Users/lengwen/Desktop/buffer.txt");
//创建文件的操作管道
FileChannel channel = fis.getChannel();
//分配一个10大小的缓冲区,其实就是分配一个10个大小的Byte数组
ByteBuffer buffer = ByteBuffer.allocate(10);
printInfo("初始化", buffer);
//将数据从通道中写到缓冲区
channel.read(buffer);
printInfo("调用read", buffer);
//把limit设置为当前的position值;把position设置为0
buffer.flip();
printInfo("调用flip", buffer);
while (buffer.remaining() > 0) {
byte b = buffer.get();
System.out.print((char) b);
}
printInfo("调用完get", buffer);
//调用clear恢复position limit
buffer.clear();
printInfo("调用clear", buffer);
fis.close();
}
private static void printInfo(String step, ByteBuffer buffer) {
System.out.println();
System.out.println("step:"+step);
System.out.println("\tcapacity:" + buffer.capacity());
System.out.println("\tposition:" + buffer.position());
System.out.println("\tlimit:" + buffer.limit());
}
}
运行结果
step:初始化
capacity:10
position:0
limit:10
step:调用read
capacity:10
position:7
limit:10
step:调用flip
capacity:10
position:0
limit:7
lengwen
step:调用完get
capacity:10
position:7
limit:7
step:调用clear
capacity:10
position:0
limit:10
看看
多谢大佬分享
强强强
感谢作者!
感谢!