文章目录
转载自 并发编程网 – ifeve.com本文链接地址: Java NIO系列教程(三) Buffer
1 概述
Buffer,即缓冲区,主要用于与NIO通道进行交互。数据从Channel读取Buffer,从Buffer写入Channel。
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
Buffer类型
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
2 基本属性
capacity
缓存区的容量,不可改变。只能往里写capacity个byte、int,char等类型。
position
当你要写数据到Buffer中时,position表示当前可写的位置。初始的position值为0(也可以用过方法进行改变)。当一个byte、int等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.
当读取数据时,也是从某个特定位置读。当从Buffer的position处读取数据完成时,position向前移动到下一个可读的位置。
limit
在写数据时,Buffer的limit表示你最多能往Buffer里写多少数据,position移动到limit写操作停止。初始limit的值等于Buffer的capacity。
当读取数据时, limit表示你最多能读到多少数据,position移动到limit读操作停止。
无论在读数据时还是在写数据时,只要position超过了limit就会抛出异常。
3 基本用法
使用Buffer读写数据一般遵循以下几个步骤:
- 1 采用allocate分配一块固定容量的缓冲区。
- 2 写入数据到Buffer
- 3 调用flip()方法,从写模式切换到读模式
- 4 从Buffer中读取数据
- 5 调用clear()方法或者compact()方法,清空缓冲区数据
3.1 DEMO
String src = "bufferTest1.txt";
RandomAccessFile r=null;
try {
r = new RandomAccessFile(src,"rw");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
FileChannel channel = r.getChannel();
// 1. 创建一块大小为8的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(8);
int len =0;
//2. 读入数据到buffer
while ((len= channel.read(buffer))!=-1){
//3 切换到读取模式
buffer.flip();
while (buffer.hasRemaining()){
// 4 每次读取一个字节
byte byte1= buffer.get();
System.out.println(byte1);
}
// 5 清空buffer
buffer.clear();
}
r.close();
3.2 获取buffer
通过allocate()方法分配一个固定容量的buffer
ByteBuffer b = ByteBuffer.allocate(8);
3.3 读取数据到Buffer
写数据到Buffer有两种方式:
- 从Channel写到Buffer。
- 通过Buffer的put()方法写到Buffer里。
channel.read(buffer))
buffer.put(some thing);//byte,byte[],buffer等
3.4 flip()
flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。
换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。
3.5 clear()与compact()
一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。
如果调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。
如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。
如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那么使用compact()方法。
&160;compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
3.6mark()与reset()方法
&160;通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。例如:
buffer.mark();
//call buffer.get() a couple of times, e.g. during parsing.
buffer.reset(); //set position back to mark.