1、Buffer的创建
Buffer的创建可以通过两种方式。使用静态方法allocate()从堆中分配缓冲区,或者是一个既有的数组中创建缓冲区:
//从堆中分配
ByteBuffer buffer = ByteBuffer.allocate(1024);
//从既有的数组中创建
byte array[] = new byte[1024];
ByteBuffer buffer = ByteBuffer.wrap(array);
2、重置和清空缓冲区
Buffer 还提供了一些用于重置和清空Buffer状态的函数,如下:
public final Buffer rewind();
public final Buffer clear();
public final Buffer flip()
以上的三个函数有着类似的功能,它们重置了Buffer对象。这里所谓的重置,只是指重置了Buffer的各项标志位,并不真正清空Buffer的内容。3个函数的功能上也有所不同。
函数rewind将position置零,并清除标志位(mark)。它的作用在于为提取Buffer的有效数据做准备:
out.write(buf) ; //从Buffer读取数据写入channel
buf.rewind(); //回滚Buffer
buf.get(array); //将Buffer的有效数据复制到数组中。
函数clear()也将Position置零,同时将Limit设置为capacity的大小,并清除了标志(mark)。由于清空了Limit,因此便无法得知Buffer内哪些数据是真实有效的。这个方法用于为重新写Buffer做准备:
buf.clear(); //为读入数据到buffer做准备。
in.read(buf); //从通道读入数据
函数flip()先将limit设置到position所在位置,然后将Position置零,并清除标志位mark.它通常在读写转换时使用。
buf.put(magic); //将magic数组写入buffer
in.read(buf); //从通道读入给定信息,存放到Buffer中。
buf.flip(); //将Buffer从写状态转为读状态
out.write(buf); //将magic和in通道中读入的信息,写到通道out中。
3、读/写缓冲区
对Buffer进行读写操作是Buffer最为重要的操作。以ByteBuffer为例,JDK提供了以下常用读写操作:
public byte get(); //返回当前postion上的数据,并将positin位置向后移一位
public ByteBuffer get(byte[] dst) //读取当前Buffer的数据到dst中,并恰当地移动position位置
public byte get(int index); //读取给定index索引上的数据,不改变postion位置 。
public ByteBuffer put(byte b) //当前位置写入给定的数据,postion位置向后移一位
public ByteBuffer put(int index,byte b) //将数据b写入当前Buffer的index位置。
public final ByteBuffer put(byte[] src) //将给定的数据写入当前Buffer.
4、标志缓冲区
标志(mark)缓冲区是一项在数据和凸显时很有用的功能,它就像书签一样,在数据处理的过程中,可以随时记录当前位置。然后在任意时刻,回到这个位置,从而加快或简化数据处理流程。
mark()用于记录当前位置,reset函数用于恢复到mark所在的位置。下面这段代码就充分了解释了这两个函数
import java.nio.ByteBuffer;
public class BufferTest {
public static void main(String[] args) {
//从堆中分配
ByteBuffer b = ByteBuffer.allocate(15);
//从既有的数组中创建
// byte array[] = new byte[1024];
// ByteBuffer buffer = ByteBuffer.wrap(array);
for(int i = 0 ;i<10;i++){
b.put((byte)i);
}
b.flip(); //准备读取数据
for (int i = 0; i < b.limit(); i++) {
System.out.print(b.get());
if(i==4){
b.mark(); //在第4个位置做mark
System.out.print("( mark at "+i+" )");
}
}
b.reset(); //回到mark的位置,并处理后续数据
System.out.println("\nreset to mark");
while(b.hasRemaining()){ //后续所有数据都将处理
System.out.print(b.get());
}
}
}
以下图是输出结果:
5、复制缓冲区
public ByteBuffer duplicate()
这个函数对处理复杂的Buffer数据很有好处。因此新生在怕缓冲区和原缓冲共享相同的内存数据,并且,对任意一方的数据改动都是相互可见的,但是两者又独立维护了各自的postion,limit 和mark。这就大大增加了程序的灵活性。
6、缓冲区分片
缓冲区分片使用slice()方法实现,它将在现有的缓冲区中,创建新的子缓冲区,子缓冲区和父缓冲区共享数据。这个方法有助于将系统模块化。
import java.nio.ByteBuffer;
public class BufferTest {
public static void main(String[] args) {
//从堆中分配
ByteBuffer b = ByteBuffer.allocate(15);
//从既有的数组中创建
// byte array[] = new byte[1024];
// ByteBuffer buffer = ByteBuffer.wrap(array);
for(int i = 0 ;i<10;i++){
b.put((byte)i);
}
b.position(2); //当前位置为2
b.limit(6); //设置上限为6
ByteBuffer subBuffer = b.slice(); //生成子缓冲区
for (int i = 0; i < subBuffer.capacity(); i++) {
byte bb = subBuffer.get(i);
bb*=10;
subBuffer.put(i,bb);
}
b.position(0);
b.limit(b.capacity());
while (b.hasRemaining()) {
System.out.print(b.get()+",");
}
}
}
7、只读缓冲区
可以使用缓冲区对象的asReadOnlyBuffer()方法得到一个与当前缓冲区一致的,并且共享内存数据的只读缓冲区。只读缓冲区对于数据安全非常有用。当缓冲区作为参数传递给对象的某个方法时,由于无法确认该方法是否会破坏缓冲区数据,此时,使用只读缓冲区可以保证数据不被修改。同时,因为只读缓冲区和原始缓冲区是共享内存块的,因此,对原始缓冲区的修改,只读缓冲区也是可见的。
import java.nio.ByteBuffer;
public class BufferTest {
public static void main(String[] args) {
//从堆中分配
ByteBuffer b = ByteBuffer.allocate(15);
//从既有的数组中创建
// byte array[] = new byte[1024];
// ByteBuffer buffer = ByteBuffer.wrap(array);
for(int i = 0 ;i<10;i++){
b.put((byte)i);
}
ByteBuffer readOnly = b.asReadOnlyBuffer(); //创建只读缓冲区
readOnly.flip();
while (readOnly.hasRemaining()) {
System.out.print(readOnly.get()+" ");
}
System.out.println();
b.put(2,(byte)20); //修改了原始缓冲区的数据
readOnly.flip();
while (readOnly.hasRemaining()) {
System.out.print(readOnly.get()+" "); //新的改动,在只读缓冲内可见
}
}
}
这里写图片描述" title="">
时间: 2024-10-11 01:52:08