NIO之缓冲区(Buffer)的数据存取
缓冲区(Buffer)
一个用于特定基本数据类行的容器。有java.nio包定义的,所有缓冲区都是抽象类Buffer的子类。
Java NIO中的Buffer主要用于与NIO通道进行交互,数据是从通道读入到缓冲区,从缓冲区写入通道中的。
Buffer就像一个数组,可以保存多个相同类型的数据。根据类型不同(boolean除外),有以下Buffer常用子类:
- ByteBuffer
- CharBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
上述Buffer类他们都采用相似的方法进行管理数据,只是各自管理的数据类型不同而已,都是通过以下方法获取一个Buffer对象:
static XxxBuffer allocate(int capacity)
创建一个容量为capacity的XxxBuffer对象。
Buffer中的重要概念
1)容量(capacity):表示Buffer最大数据容量,缓冲区容量不能为负,并且建立后不能修改。
2)限制(limit):第一个不应该读取或者写入的数据的索引,即位于limit后的数据不可以读写。缓冲区的限制不能为负,并且不能大于其容量(capacity)。
3)位置(position):下一个要读取或写入的数据的索引。缓冲区的位置不能为负,并且不能大于其限制(limit)。
4)标记(mark)与重置(reset):标记是一个索引,通过Buffer中的mark()方法指定Buffer中一个特定的position,之后可以通过调用reset()方法恢复到这个position。
注意:0<=mark<=position<=limit<=capacity
测试代码:
package com.dx.nios; import java.nio.ByteBuffer; import org.junit.Test; public class BufferTest { @Test public void TestBuffer() { ByteBuffer byteBuffer = ByteBuffer.allocate(10); System.out.println("------------allocate------------------"); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); byteBuffer.put("abcde".getBytes()); System.out.println("------------put------------------"); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); byteBuffer.flip(); System.out.println("------------flip------------------"); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); } }
输出结果:
------------allocate------------------ 10 ------------put------------------ 10 ------------flip------------------ 5
分析:
Buffer常用函数介绍及测试
clear()方法
clear()方法用于写模式,其作用为情况Buffer中的内容,所谓清空是指写上限与Buffer的真实容量相同,即limit==capacity,同时将当前写位置置为最前端下标为0处。代码如下:
public final Buffer clear() { position = 0; //设置当前下标为0 limit = capacity; //设置写越界位置与和Buffer容量相同 mark = -1; //取消标记 return this; }
rewind()方法
rewind()在读写模式下都可用,它单纯的将当前位置置0,同时取消mark标记,仅此而已;也就是说写模式下limit仍保持与Buffer容量相同,只是重头写而已;读模式下limit仍然与rewind()调用之前相同,也就是为flip()调用之前写模式下的position的最后位置,flip()调用后此位置变为了读模式的limit位置,即越界位置,代码如下:
public final Buffer rewind() { position = 0; mark = -1; return this; }
flip()方法
flip()函数的作用是将写模式转变为读模式,即将写模式下的Buffer中内容的最后位置变为读模式下的limit位置,作为读越界位置,同时将当前读位置置为0,表示转换后重头开始读,同时再消除写模式下的mark标记,代码如下
public final Buffer flip() { limit = position; position = 0; mark = -1; return this; }
测试
package com.dx.nios; import java.nio.ByteBuffer; import org.junit.Test; public class BufferTest { @Test public void TestBuffer() { // 1.使用allocate()申请10个字节的缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(10); System.out.println("------------allocate------------------"); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); // 2.使用put()存放5个字节到缓冲区 byteBuffer.put("abcde".getBytes()); System.out.println("------------put------------------"); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); // 3.切换到读取数据模式 byteBuffer.flip(); System.out.println("------------flip------------------"); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); // 4.从缓冲区中读取数据 System.out.println("------------get------------------"); byte[] bytes = new byte[byteBuffer.limit()]; byteBuffer.get(bytes); System.out.println(new String(bytes, 0, bytes.length)); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); // 5.设置为可重复读取 System.out.println("------------rewind------------------"); byteBuffer.rewind(); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); byte[] bytes2 = new byte[byteBuffer.limit()]; byteBuffer.get(bytes2); System.out.println(new String(bytes2, 0, bytes2.length)); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); // 6。clear清空缓存区,但是内容没有被清掉,还存在。只不过这些数据状态为被遗忘状态。 System.out.println("------------clear------------------"); byteBuffer.clear(); System.out.println(byteBuffer.position()); System.out.println(byteBuffer.limit()); System.out.println(byteBuffer.capacity()); byte[] bytes3 = new byte[10]; byteBuffer.get(bytes3); System.out.println(new String(bytes3, 0, bytes3.length)); } }
输出:
------------allocate------------------ 0 10 10 ------------put------------------ 5 10 10 ------------flip------------------ 0 5 10 ------------get------------------ abcde 5 5 10 ------------rewind------------------ 0 5 10 abcde 5 5 10 ------------clear------------------ 0 10 10 abcde
mark与reset的用法
public static void main(String[] args){ ByteBuffer byteBuffer = ByteBuffer.allocate(1024); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capcity"+byteBuffer.capacity()); System.out.println("--------------------------------"); String str = "从工单里来的状态"; for (int i = 0; i < 1; i++) { str+="尚未完成"; } System.out.println("写入数据"); byteBuffer.put(str.getBytes()); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capcity"+byteBuffer.capacity()); System.out.println("--------------------------------"); System.out.println("转换为读模式"); byteBuffer.flip(); byte[] bts = new byte[3];// byte数组设置的越大,一次就能放置更多的数据,但也不能太大,会影响传输,一般就是1024,这里故意设置小点为了测试 byteBuffer.get(bts);// 方法名容易让我误解,其实是把数据填充进byte数组 System.out.println("读取一个字符:"+new String(bts,0,bts.length)); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capcity"+byteBuffer.capacity()); byteBuffer.get(bts); System.out.println("再次读取一个字符:"+new String(bts,0,bts.length)); System.out.println("mark前"); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capcity"+byteBuffer.capacity()); System.out.println("标记当前position位置"); byteBuffer.mark(); byteBuffer.get(bts);// 标记后,reset前再读取一次 System.out.println("mark后"); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capcity"+byteBuffer.capacity()); System.out.println("恢复当前position位置为之前标记的位置"); byteBuffer.reset(); System.out.println("reset后"); System.out.println("position:"+byteBuffer.position()); System.out.println("limit:"+byteBuffer.limit()); System.out.println("capcity"+byteBuffer.capacity()); System.out.println("reset后的position应该和mark前的poisition相等"); System.out.println("--------------------------------"); }
打印信息:
position:0 limit:1024 capcity1024 -------------------------------- 写入数据 position:36 limit:1024 capcity1024 -------------------------------- 转换为读模式 读取一个字符:从 position:3 limit:36 capcity1024 再次读取一个字符:工 mark前 position:6 limit:36 capcity1024 标记当前position位置 mark后 position:9 limit:36 capcity1024 恢复当前position位置为之前标记的位置 reset后 position:6 limit:36 capcity1024 reset后的position应该和mark前的poisition相等 --------------------------------