JAVA NIO之Buffer
Buffer就是一个数据存储器。数据可以存储在其中并在之后用于检索。
在Buffer的源码中可以看到:
// Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity;
这四个就是缓冲区的重要属性。
容量(Capacity):缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变。
上界(Limit):缓冲区的第一个不能被读或写的元素。或者说,limit后既不可读也不可写。
位置(Position):下一个要被读或写的元素的索引。位置会自动由相应的 get( )和 put( )函数更新。
标记(Mark):一个备忘位置。调用 mark( )来设定 mark = postion。调用 reset( )设定 position =mark。标记在设定前是未定义的(undefined)。
Buffer类的api方法:
除了boolean其他基本类型都有相应的buffer。常用的为CharBuffer、ByteBuffer。下面是一个简化的类图。
下面我们就来实际操作buffer,以CharBuffer为例。
1.创建一个CharBuffer
CharBuffer charBuffer = CharBuffer.allocate(10); System.out.println("容量capacity="+charBuffer.capacity()+" 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:容量capacity=10 界限limit=10 位置position=0,关系如下如图
2.向上面的buffer添加四个元素。
charBuffer.put("q"); charBuffer.put("w"); charBuffer.put("e"); charBuffer.put("r"); //加入四个元素 输出:界限limit=10 位置position=4 System.out.println("加入四个元素 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:加入四个元素 界限limit=10 位置position=4,关系如下图
3.调用flip()方法,Buffer从写模式切换到读模式,将limit设置为position,position设为0。
charBuffer.flip(); //输出:界限limit=4 位置position=0 System.out.println("flip()后:界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:flip()后 :界限limit=4 位置position=0,关系如下图
4.此时buffer为可读,我们从中读取数据。
//取出第一个元素 System.out.println("相对取出一个元素get():"+charBuffer.get()); //界限limit=4 位置position=1 System.out.println("相对取出一个元素get()后: 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:相对取出一个元素get()后: 界限limit=4 位置position=1,关系如下图。
5.调用clear()让buffer回到写模式,clear()将limit变为capacity,position=0,上面添加的数据依然存在buffer中。
//clear()将limit变为capacity,position=0,数据依然存在 charBuffer.clear(); //界限limit=10 位置position=0 System.out.println("clear()后:界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:clear()后:界限limit=10 位置position=0,关系如下图,和初始时相似,但现在buffer里有数据。
6.根据索引绝对访问get(x),取值不会影响position
//get(3)根据索引取值不会影响position System.out.println("根据索引绝对访问get(1)="+charBuffer.get(3)); System.out.println("根据索引绝对访问get(1)后: 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:根据索引绝对访问get(1)=r;根据索引绝对访问get(1)后: 界限limit=10 位置position=0
7.buffer的释放。释放有两种方式:
a.)
CharBuffer buffer1 = CharBuffer.allocate(8); buffer1.put("a"); buffer1.put("b"); buffer1.put("c"); buffer1.flip(); //释放1,布尔函数 hasRemaining()会在释放缓冲区时判断是否已经达到缓冲区的上界 char[] receive1 = new char[32]; for(int i = 0;buffer1.hasRemaining();i++){ receive1[i] =buffer1.get(); System.out.println("释放1 hasRemaining:receive["+i+"]="+receive1[i]); }
b.)
CharBuffer buffer2 = CharBuffer.allocate(8); buffer2.put("1"); buffer2.put("2"); buffer2.put("3"); buffer2.flip(); //释放2,remaining()函数:从当前位置到上界还剩余的元素数目 int count = buffer2.remaining(); char[] receive2 = new char[32]; for (int i=0;i<count;i++){ receive2[i] =buffer2.get(); System.out.println("释放2 remaining:receive["+i+"]="+receive2[i]); }
8.批量移动,上面说的方式移动数据效率不高,NIO的buffer还提供了更加高效的方式。
package com.nio.java; import java.nio.CharBuffer; /** * 批量移动数据 * @author monkjavaer * @date 2018/10/16 15:29 */ public class BufferTest2 { public static void main(String[] args) { CharBuffer charBuffer = CharBuffer.allocate(10); System.out.println("容量capacity="+charBuffer.capacity()+" 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position()); charBuffer.put("q"); charBuffer.put("w"); charBuffer.put("e"); charBuffer.put("r"); charBuffer.put("t"); charBuffer.flip(); ////buffer.get(smallArray);等价于:buffer.get(smallArray,0,smallArray.length); //如果数组比较小不能装下待处理的数据,就需要指定长度,否则buffer.get(smallArray)会抛出java.nio.BufferUnderflowException char [] smallArray = new char [2]; while (charBuffer.hasRemaining( )) { int length = Math.min (charBuffer.remaining( ), smallArray.length); System.out.println("length="+length); charBuffer.get (smallArray, 0, length); processData(smallArray,length); } } /** * 处理数据 * @param smallArray * @param length 数组中有多少待处理数据 */ public static void processData(char [] smallArray,int length){ System.out.println("===processData===="); for (int j =0 ;j<length;j++) { System.out.println("smallArray["+j+"]="+smallArray[j]); } } }