Buffers
缓冲区(Buffers)本质上是一个可以写入数据的内存块,然后可以读取。 这个内存块包含在NIO Buffer对象中,该对象提供了一组api,这样可以方便用户更轻松地使用内存块。
在NIO中已实现的buffer类中继承Buffer这个抽象类
public abstract class Buffer {
// Cached unsafe-access object
static final Unsafe UNSAFE = Unsafe.getUnsafe();
/**
* The characteristics of Spliterators that traverse and split elements
* maintained in Buffers.
*/
static final int SPLITERATOR_CHARACTERISTICS =
Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
//略。。。
}
其他具体的实现方式,根据不同的需求实现例如
ByteBuffer底层使用的为byte数组
CharBuffer使用char数组
DirectByteBuffer使用直接内存,这里通过从抽象类中的Unsafe 类分配直接内存使用。
- 缓冲的基本用法:下面是最基本的四步
- 向buffer写入数据
- 调用buffer.flip() 方法反转
- 读取buffer中的数据
- 调用buffer.clear() 或者buffer.compact()清楚
当数据写入缓冲区时,缓冲区会跟踪写入的数据量(在buffer对象中有position 会跟踪写入点)。 一旦需要读取数据,就需要使用flip() 方法调用将缓冲区从写入模式切换到读模式。 在读模式下,缓冲区允许读取已经写入缓冲区的所有数据。一旦读完所有数据,需要清除缓冲区,以便再次写入。 可以通过两种方式执行:调用clear()或调用compact() 方法。 clear() 方法清除整个缓冲区。 compact()方法仅清除已读取的数据。 任何还没读的数据都会移动到缓冲区的开头,接下来写入时,就会在这些未读数据之后写入。
下面用一个简单的例子来说明
public class ReadFile {
public static void main(String[] args){
readFile();
}
public static void readFile(){
try(RandomAccessFile randomAccessFile =
new RandomAccessFile("F:\\data\\test.txt","rw")){
//获取连接通道
FileChannel fileChannel = randomAccessFile.getChannel();
//初始化一个缓冲区,大小为1024byte
ByteBuffer buf = ByteBuffer.allocate(1024);
//fileChannel.read(buf)从通道中读取文件的数据放入缓冲区,返回结构为读取的字节数
//注意:这个方法会记录读取的位置,所以后续读取不会从头开始读取
int bytesRead = fileChannel.read(buf);
System.out.println(bytesRead);
//读取到数据
while(bytesRead != -1)
{
//反转后为可以读取缓冲中的数据
buf.flip();
while(buf.hasRemaining())//position < limit;表示可读
{
//读取
System.out.print((char)buf.get());
}
//没有可读数据后,清除已读数据,从未读数据之后开始写入
buf.compact();
//开始继续读取
bytesRead = fileChannel.read(buf);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
说明Buffer 中的Capacity, Position 和Limit之间的关系
如下图分别表示写入和读取操作的buffer
图片.png
- Capacity
缓冲区具有一定的固定大小,也称为“容量”。 表示缓冲区的大小,也是buffer所能存储的最大容量 - Position
写操作: 在数据写入缓冲区的时候,可以选择在某个位置执行此写入操作。 如果写入时没有选择相应的位置,会默认从最初位置0开始写入,每当一个字节,字符或者整数等等写入缓冲区时,position会自动被指向缓冲区中的下一个单元为了下次插入数据。 位置最大可以变为容量 -1。为-1时表示已经写满了,不可再写入。
读操作: 从缓冲区读取数据时,也可以从指定的位置开始读取数据。 当缓冲区从写入模式翻转到读取模式时(调用flip方法),位置position将重置为0.。同理,当从缓冲区读取数据时,将从position位置开始读取数据,并将自动将position移动到下一个要读取的位置。 - Limit
写模式: limit的作用是限制写入缓冲区的数据量。写入时等于Capacity大小
读模式:缓冲区翻转为读取模式时,限制意味着可以从数据中读取的数据量的限制。 所以,当Buffer翻转到读取模式时,limit会被设置为写模式的写入位置。 换句话说,就是可以读取写入的字节数(限制设置为写入的字节数,由位置标记)。
关于Buffer中方法下一节详解
网友评论