关于NIO中的Buffer缓冲区

Buffer是一个对象,它包含一些要写入或者读取的数据。在NIO类库中加入Buffer对象,体现了新库与原IO的一个重要的区别。在面向流的IO中,可以将数据直接写入或者读取到Stream对象中。在NIO库中,所有的数据都是用缓冲区处理的(读写)。缓冲区实质上是一个数组,通常它是一个字节数组(ByteBuffer),也可以使用其他类型的数组。这个数组为缓冲区提供了数据的访问读写等操作属性,如位置、容量、上限等概念,可以参考一下API文档。

Buffer类型:我们最常用的就是ByteBuffer,实际上每一种java的基本类型都对应着一种缓冲区(除了Boolean类型)

ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。

下面我们以IntBuffer来举例怎么使用缓冲区,因为每一种Buffer的使用都是差不多滴。

1、基本操作
//创建指定长度的缓冲区
IntBuffer buf = IntBuffer.allocate(10);
//positoin表示当前位置
buf.put(11); //添加后,position由0变为1
buf.put(22);  //position位置: 1->2
buf.put(33);  //position位置: 2->3
//flip方法会将position位置复位为0 也就是3->0
buf.flip();
System.out.println("使用flip复位后:"+buf);
System.out.println("缓冲区容量为:"+buf.capacity()); //容量一旦初始化后不允许改变(warp方法包裹数组除外)
System.out.println("缓冲区的限制为:"+buf.limit());//由于只装载了三个元素,所以可读取或者操作的元素为3,则limit=3
		
System.out.println("获取下标为1的元素:"+buf.get(1));
System.out.println("get(index)方法获取后,position位置不变:"+buf);
buf.put(1,12);  //会覆盖原来index为1的值
System.out.println("put(index,change)方法添加后,position位置不变:"+buf);
for(int i=0;i<buf.limit();i++){
	//调用get方法会使其缓冲区位置(position)向后递增一位
	//如果上面没有调用flip复位position是会报错的
	System.out.print(buf.get()+"\t");
}
System.out.println("buf对象遍历之后:"+buf);
执行结果:
使用flip复位后:java.nio.HeapIntBuffer[pos=0 lim=3 cap=10]
缓冲区容量为:10
缓冲区的限制为:3
获取下标为1的元素:22
get(index)方法获取后,position位置不变:java.nio.HeapIntBuffer[pos=0 lim=3 cap=10]
put(index,change)方法添加后,position位置不变:java.nio.HeapIntBuffer[pos=0 lim=3 cap=10]
11	12	33	buf对象遍历之后:java.nio.HeapIntBuffer[pos=3 lim=3 cap=10]
总结:我们需要注意的是position位置。每用put(value)方法添加元素到缓冲区,positon都会加1。而get()方法,不是get(index),是根据position位置来获取缓冲区的元素的。如果一共有10个元素,但是position此时为3,那么就是从index为3的位置开始获取,而每次调用完get()方法后,position会后移一位。而get(index)不需要理会position,因为会根据传入的index获取。


2、wrap包裹方法:wrap方法会包裹一个数组:一般这种用法不会先初始化缓存对象的长度,因为是没有意义的,最后缓冲区会被wrap所包裹的数组覆盖掉,并且wrap方法修改缓冲区对象的时候,数组本身会跟着发生变化
int[] arr = new int[]{1,2,3};
IntBuffer buf = IntBuffer.wrap(arr);
System.out.println("wrap(arr)方法的缓冲区:"+buf);
buf.put(1, 6); //将缓冲区index为1的数据修改为6
System.out.println(arr[1]); //发现,数组indexi为1也确实被改为6了

执行结果:

wrap(arr)方法的缓冲区:java.nio.HeapIntBuffer[pos=0 lim=3 cap=3]
6
wrap(arr,offset,length)方法的缓冲区:java.nio.HeapIntBuffer[pos=0 lim=2 cap=3]
需要注意的是:我们可以看到wrap方法如果带上包裹的初始位置和长度,那么litmit就会是可操作元素的个数,而不是被包裹数组的长度了

3、其他方法

IntBuffer buf = IntBuffer.allocate(10);
int[] arr = new int[]{1,2,3};
buf.put(arr);
System.out.println(buf);
//复制方法
IntBuffer buf2 = buf.duplicate();
System.out.println("复制后的新缓冲区:"+buf2);
		
//设置position的方法
System.out.println("设置position前的缓冲区:"+buf);
//可读数据是直接调用get()方法能获取饿数据,而不是get(index)方法
//此时因为调用过put将数组添加到缓冲区,而数组的个数是3,所以position此时肯定是为3的
//而IntBuffer初始化的长度为10,所以可读数据个数应该为7
System.out.println("重新设置position之前的可读数据个数:"+buf.remaining());
System.out.println();
buf.position(1);
System.out.println("设置position后的缓冲区:"+buf);
//重新设置后的position为1,所以可读数据个数为9
System.out.println("重新设置position之后的可读数据个数:"+buf.remaining());
			
//将缓冲区的数据放入数组里面
int[] arr2 = new int[buf.remaining()];
buf.get(arr2);  
//由于上面是重新设置position为1,所以是将1及1之后的元素放入数组里面
//所以数组里面会有9个元素
for(int i : arr2){
	System.out.println(Integer.toString(i)+",");
}

执行结果:

java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
复制后的新缓冲区:java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]

设置position前的缓冲区:java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
重新设置position之前的可读数据个数:7
设置position后的缓冲区:java.nio.HeapIntBuffer[pos=1 lim=10 cap=10]
重新设置position之后的可读数据个数:9

2,
3,
0,
0,
0,
0,
0,
0,
0,


猜你喜欢

转载自blog.csdn.net/howinfun/article/details/80887996