Buffer 类(缓冲区)
Buffer 是一个对象,它对某种基本类型的数组进行了封装。NIO 开始使用的 Channel(通道)就是通过 Buffer 来读写数据的;
在 NIO 中,所有的数据都是用 Buffer 处理的,它是 NIO 读写数据的中转池。Buffer 实质上是一个数组,通常是一个字节数据,但也可以是其他类型的数组。但一个缓冲区不仅仅是一个数组,重要的是它提供了对数据的结构化访问,而且还可以跟踪系统的读写进程;
使用 Buffer 读写数据一般遵循以下四个步骤: 1.写入数据到 Buffer; 2.调用 flip() 方法; 3.从 Buffer 中读取数据; 4.调用 clear() 方法或者 compact() 方法。
当向 Buffer 写入数据时,Buffer 会记录下写了多少数据。一旦要读取数据,需要通过 flip() 方法将 Buffer 从写模式切换到读模式。在读模式下,可以读取之前写入到 Buffer 的所有数据;
一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用 clear() 或 compact() 方法。clear() 方法会清空整个缓冲区。compact() 方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面;
Buffer主要有如下几种:
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
1. 创建 ByteBuffer
ByteBuffer 类内部封装了一个 byte[] 数组,并可以通过一些方法对这个数组进行操作;
创建 ByteBuffer 对象:
方式一:在堆中创建缓冲区:allocate(int capacity)
,例如 ByteBuffer byteBuffer = ByteBuffer.allocate(10);
,在堆中创建缓冲区称为:间接缓冲区;
方式二:在系统内存创建缓冲区:allocatDirect(int capacity)
,例如 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10);
,在系统内存创建缓冲区称为:直接缓冲区,间接缓冲区的创建和销毁效率要高于直接缓冲区,间接缓冲区的工作效率要低于直接缓冲区;
方式三:通过数组创建缓冲区:wrap(byte[] arr)
,例如 byte[] byteArray = new byte[10]; ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
,通过数组创建的缓冲区为:间接缓冲区;
2. 向 ByteBuffer 添加数据
向当前可用位置添加数据:public ByteBuffer put(byte b)
;
import java. nio. ByteBuffer;
import java. util. Arrays;
public class Test {
public static void main ( String[ ] args) {
ByteBuffer buf = ByteBuffer. allocate ( 10 ) ;
buf. put ( ( byte ) 10 ) ;
buf. put ( ( byte ) 20 ) ;
System. out. println ( Arrays. toString ( buf. array ( ) ) ) ;
}
}
向当前可用位置添加一个 byte[] 数组:public ByteBuffer put(byte[] byteArray)
;
import java. nio. ByteBuffer;
import java. util. Arrays;
public class Test {
public static void main ( String[ ] args) {
ByteBuffer buf = ByteBuffer. allocate ( 10 ) ;
buf. put ( ( byte ) 10 ) ;
buf. put ( ( byte ) 20 ) ;
byte [ ] byteArray = { 30 , 40 , 50 } ;
buf. put ( byteArray) ;
System. out. println ( Arrays. toString ( buf. array ( ) ) ) ;
}
}
添加一个 byte[] 数组的一部分:public ByteBuffer put(byte[] byteArray,int offset,int len)
;
import java. nio. ByteBuffer;
import java. util. Arrays;
public class Test {
public static void main ( String[ ] args) {
ByteBuffer buf = ByteBuffer. allocate ( 10 ) ;
buf. put ( ( byte ) 10 ) ;
buf. put ( ( byte ) 20 ) ;
byte [ ] byteArray = { 30 , 40 , 50 } ;
buf. put ( byteArray, 0 , 2 ) ;
System. out. println ( Arrays. toString ( buf. array ( ) ) ) ;
}
}
3. 容量 capacity
Buffer 的容量(capacity)是指:Buffer 所能够包含的元素的最大数量。定义了 Buffer 后,容量是不可变的;
import java. nio. ByteBuffer;
public class Test {
public static void main ( String[ ] args) {
ByteBuffer b1 = ByteBuffer. allocate ( 10 ) ;
System. out. println ( "容量:" + b1. capacity ( ) ) ;
byte [ ] byteArray = { 97 , 98 , 99 , 100 } ;
ByteBuffer b2 = ByteBuffer. wrap ( byteArray) ;
System. out. println ( "容量:" + b2. capacity ( ) ) ;
}
}
4. 限制 limit
限制 limit 是指:第一个不应该读取或写入元素的 index 索引。缓冲区的限制(limit)不能为负,并且不能大于容量;
有两个相关方法:
获取此缓冲区的限制:public int limit()
;
设置此缓冲区的限制:public Buffer limit(int newLimit)
;
import java. nio. ByteBuffer;
public class Test {
public static void main ( String[ ] args) {
ByteBuffer buf = ByteBuffer. allocate ( 10 ) ;
System. out. println ( "初始容量:" + buf. capacity ( ) +
" 初始限制:" + buf. limit ( ) ) ;
buf. limit ( 3 ) ;
buf. put ( ( byte ) 10 ) ;
buf. put ( ( byte ) 20 ) ;
buf. put ( ( byte ) 30 ) ;
buf. put ( ( byte ) 40 ) ;
}
}
5. 位置 position
位置 position 是指:当前可写入的索引。位置不能小于 0,并且不能大于"限制";
有两个相关方法:
获取当前可写入位置索引:public int position()
;
更改当前可写入位置索引:public Buffer position(int p)
;
import java. nio. ByteBuffer;
import java. util. Arrays;
public class Test {
public static void main ( String[ ] args) {
ByteBuffer buf = ByteBuffer. allocate ( 10 ) ;
System. out. println ( "初始容量:" + buf. capacity ( ) +
" 初始限制:" + buf. limit ( ) +
" 当前位置:" + buf. position ( ) ) ;
buf. put ( ( byte ) 10 ) ;
buf. put ( ( byte ) 20 ) ;
buf. put ( ( byte ) 30 ) ;
System. out. println ( "当前容量:" + buf. capacity ( ) +
" 初始限制:" + buf. limit ( ) +
" 当前位置:" + buf. position ( ) ) ;
buf. position ( 1 ) ;
buf. put ( ( byte ) 2 ) ;
buf. put ( ( byte ) 3 ) ;
System. out. println ( Arrays. toString ( buf. array ( ) ) ) ;
}
}
6. 标记 mark
标记 mark 是指:当调用缓冲区的 reset() 方法时,会将缓冲区的 position 位置重置为该索引。不能为 0,不能大于 position;
相关方法:
设置此缓冲区的标记为当前的 position 位置:public Buffer mark()
;
import java. nio. ByteBuffer;
import java. util. Arrays;
public class Test {
public static void main ( String[ ] args) {
ByteBuffer buf = ByteBuffer. allocate ( 10 ) ;
System. out. println ( "初始容量:" + buf. capacity ( ) +
" 初始限制:" + buf. limit ( ) +
" 当前位置:" + buf. position ( ) ) ;
buf. put ( ( byte ) 10 ) ;
buf. put ( ( byte ) 20 ) ;
buf. put ( ( byte ) 30 ) ;
System. out. println ( "当前容量:" + buf. capacity ( ) +
" 当前限制:" + buf. limit ( ) +
" 当前位置:" + buf. position ( ) ) ;
buf. position ( 1 ) ;
buf. mark ( ) ;
buf. put ( ( byte ) 2 ) ;
buf. put ( ( byte ) 3 ) ;
buf. reset ( ) ;
System. out. println ( "reset后的当前位置:" + buf. position ( ) ) ;
buf. put ( ( byte ) 20 ) ;
System. out. println ( Arrays. toString ( buf. array ( ) ) ) ;
}
}
7. 其它方法
获取 position 与 limit 之间的元素数:public int remaining()
;
获取当前缓冲区是否只读:public boolean isReadOnly()
;
获取当前缓冲区是否为直接缓冲区:public boolean isDirect()
;
还原缓冲区的状态:public Buffer clear()
:
将 position 设置为 0;
将限制 limit 设置为容量 capacity;
丢弃标记 mark;
缩小 limit 的范围:public Buffer flip()
;
将 limit 设置为当前 position 位置;
将当前 position 位置设置为 0;
丢弃标记;
重绕此缓冲区:public Buffer rewind()
;
将 position 位置设置为 0;
限制 limit 不变;
丢弃标记;