• 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]);
            }
        }
    }
    
  • 相关阅读:
    WEB API&API
    event flow
    JS-for的衍生对象
    JS-function
    Object Constructor
    前端发展史
    JavaScript中document.getElementById和document.write
    正则表达式把Paul换成Ringo
    11th blog
    10th week blog
  • 原文地址:https://www.cnblogs.com/monkjavaer/p/9806622.html
Copyright © 2020-2023  润新知