Buffer是缓存,Buffer的作用是和NIO通道(Channel)进行交互。
查阅资料知道:
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
Buffer的使用
总共分为四步:
1.写数据到Buffer
2.调用flip()方法
3.从Buffer中读取数据
4.调用clear()方法或者compact()方法
上一篇文章写Channel测试的时候也简单使用了Buffer。这里说一下clear()和compact()方法。他们都可以在读取完毕之后清空缓存区,为以后的数据写入做准备,他们的区别在于:clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。未读过的数据会留在缓存区中,随着后面读入的数据一起等下一次的filp()。
这里用代码简单的使用一下:
public class TestBuffer {
public static void main(String[] args) throws IOException {
Charset charset = Charset.forName("utf-8");
CharsetDecoder decoder = charset.newDecoder();
RandomAccessFile file = new RandomAccessFile("nio-data.txt","rw");
FileChannel channel = file.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48);
CharBuffer cb = CharBuffer.allocate(48);
int count = channel.read(buf);
while (count!=-1){
buf.flip();
decoder.decode(buf,cb,false);
cb.flip();
while (cb.hasRemaining()){
System.out.print(cb.get());
}
buf.compact();
cb.compact();
count = channel.read(buf);
}
file.close();
}
}
这里我开始使用compact()而不是clear()了。
接下来学习一下Buffer的原理
它有三个重要的属性:
- capacity(容量)
- position(位置)
- limit(界限)
position和limit的含义取决于Buffer处在读模式还是写模式。
capacity不然。
capacity(容量)
翻译来是容量,很好理解,既然是容量就又固定的大小,一旦Buffer满了,我们就需要对其清空,然后才能继续使用它。
position(位置)
写模式:position表示数据当前的位置,会随着数据的写入不断的移动,直到达到容量,position最大为capacity-1。
读模式:当我们读取数据时,Buffer会从写模式切换到读模式,然后position会清0,position会移动到可读的位置。
limit(界限)
写模式:limit表示我们还能向Buffer中写多少数据,此模式下limit等于capacity。
读模式:此模式下,limit表示我们可以从Buffer度多少数据,此时limit会设置为写模式下的position值。
其实有数据结构的线性结构的思想,理解起来就会很简单,可以通过复习数组、链表、队列和栈来回忆~
Buffer使用(细化)
为Buffer分配空间
前面练习有对Buffer分配空间的代码,这里提取出来单独记:
ByteBuffer buf = ByteBuffer.allocate(48);
这就分配好了,这里只是Byte类型,我们还可以使用很多基本类型的buffer,就是可以通过char,short,int,long,float 或 double类型来操作缓冲区中的字节。
向Buffer写数据
我们可以选择两种方式去写数据:
1.用Channel向Buffer写
int bytesRead = inChannel.read(buf); //read into buffer.
2.用Buffer自带的put()方法
buf.put(127);
从Buffer读数据
这之前先说个filp()方法,filp()这个办法,会将Buffer从写模式切换成读模式,将position设置为0,并将limit设置成之前position的值,也就是说:position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。
读数据也有两种方式:
1.从Channel里读
int bytesWritten = inChannel.write(buf);
2.用Buffer的get()方法
byte aByte = buf.get();
记一下rewind()方法
Buffer.rewind()会将position设回0,所以使用后,我们可以重读Buffer中的所有数据。
记一下clear()与compact()方法
前面有简单的记过,这里具体说一说,当我们读完buffer中的数据之后,要将缓存清空,这时候就需要使用到这俩方法,可以根据实际情况任选其一~
clear()是清除所有的缓存。
compact()是清除已经读过的缓存。
clear()会把position设回0,limit被设置成 capacity的值。
compact()将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。
记一下mark()与reset()方法
buffer.mark();
buffer.reset();
通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。
equals()与compareTo()方法
先说equals()
Q:什么情况下equals()返回true呢?
A:需要满足以下情况:
1.类型相同
2.Buffer中剩余的byte、char等的个数相同
3.Buffer中所有剩余的byte、char等都相同。
所以Buffer中,equals(),比较的是Buffer的剩余部分
Q:compareTo()方法是啥?
A:compareTo是比较两个Buffer的剩余元素的(byte、char等)
什么情况下一个Buffer小于另一个Buffer呢?
1.第一个不相等的元素小于另一个Buffer中对应的元素 。
2.所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。
Scatter和Gather
这里yi