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]);
        }
    }
}

 

posted @ 2018-10-17 23:33  monkjavaer  阅读(301)  评论(0编辑  收藏  举报