zoukankan      html  css  js  c++  java
  • 2、NIO--缓冲区(Buffer)

    缓冲区(BUffer)

    缓冲区(Buffer:一个用于特定基本数据类
    型的容器。由 java.nio 包定义的,所有缓冲区
    都是 Buffer 抽象类的子类。

    Java NIO 中的 Buffer 主要用于与 NIO 通道进行
    交互,数据是从通道读入缓冲区,从缓冲区写
    入通道中的。

    缓冲区:在NIO中负责数据的存取,说白了就是数组用于储存不同类型的数组

    根据数据类型不同(boolean类型除外),提供了相应的类型的缓冲区

     ByteBuffer
     CharBuffer
     ShortBuffer
     IntBuffer
     LongBuffer
     FloatBuffer
     DoubleBuffer

    上述Buffer类他们都采用相拟的方法进行管理数据

    只是各自管理的数据类不同而已

    的都是通过同一个方法获取Buffer对象:

    static XxxBuffer allocate(int capacity) : 创建一个容量为 capacity 的 XxxBuffer 对象

    ByteBuffer buf = ByteBuffer.allocate(1024);
    

      

    缓冲区存取数据的两个核心方法:

    1、put():存入数据到缓冲区

        public final ByteBuffer put(byte[] src) {
            return put(src, 0, src.length);
        }
        public ByteBuffer put(byte[] src, int offset, int length) {
            checkBounds(offset, length, src.length);
            if (length > remaining())
                throw new BufferOverflowException();
            int end = offset + length;
            for (int i = offset; i < end; i++)
                this.put(src[i]);
            return this;
        }

    2、get():获取缓冲区中的数据

        public ByteBuffer get(byte[] dst) {
            return get(dst, 0, dst.length);
        }
        public ByteBuffer get(byte[] dst, int offset, int length) {
            checkBounds(offset, length, dst.length);
            if (length > remaining())
                throw new BufferUnderflowException();
            int end = offset + length;
            for (int i = offset; i < end; i++)
                dst[i] = get();
            return this;
        }

    缓冲区中的四个核心属性

    public abstract class java.nio.Buffer {
      
      // Field descriptor #20 I
      static final int SPLITERATOR_CHARACTERISTICS = 16464;
      
      // Field descriptor #20 I
      private int mark;
      
      // Field descriptor #20 I
      private int position;
      
      // Field descriptor #20 I
      private int limit;
      
      // Field descriptor #20 I
      private int capacity;
      ...

    容量 (capacity) :表示 Buffer 最大数据容量,缓冲区容量不能为负,并且创
      建后不能更改。


    限制 (limit):第一个不应该读取或写入的数据的索引,即位于 limit 后的数据
      不可读写。缓冲区的限制不能为负,并且不能大于其容量


    位置 (position):下一个要读取或写入的数据的索引。缓冲区的位置不能为
      负,并且不能大于其限制


    标记 (mark)与重置 (reset):标记是一个索引,通过 Buffer 中的 mark() 方法
      指定 Buffer 中一个特定的 position,之后可以通过调用 reset() 方法恢复到这
      个 position.

    标记、位置、限制、容量遵守以下不变式: 0 <= mark <= position <= limit <= capacity

        public static void main(String[] args) {
            
            //1、分配一个指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            
            System.out.println(buf.position());//0
            System.out.println(buf.limit());//1024
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=0 lim=1024 cap=1024]
       }    

    相关测试以及源码

    1、--------------------------------------------------------

    allocate源码:

        public static ByteBuffer allocate(int capacity) {
            if (capacity < 0)
                throw new IllegalArgumentException();
            return new HeapByteBuffer(capacity, capacity);
        }
    HeapByteBuffer(int cap, int lim) {            // package-private
            super(-1, 0, lim, cap, new byte[cap], 0);
            /*
            hb = new byte[cap];
            offset = 0;
            */
        }
        public static void main(String[] args) {
            
            //1、分配一个指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            
            System.out.println(buf.position());//0
            System.out.println(buf.limit());//1024
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=0 lim=1024 cap=1024]
            
            //2、利用put()方法进行存储数据
            String str = "hello nio";
            buf.put(str.getBytes());
            
            System.out.println(buf.position());//9
            System.out.println(buf.limit());//1024
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=9 lim=1024 cap=1024]
        }

    2、--------------------------------------------------------

        public static void main(String[] args) {
            
            //1、分配一个指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            
            System.out.println(buf.position());//0
            System.out.println(buf.limit());//1024
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=0 lim=1024 cap=1024]
            
            //2、利用put()方法进行存储数据
            String str = "hello nio";//9字节
            buf.put(str.getBytes());
            
            System.out.println(buf.position());//9
            System.out.println(buf.limit());//1024
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=9 lim=1024 cap=1024]
            
            //3、切换读取数据的模式
            buf.flip();
            System.out.println(buf.position());//0
            System.out.println(buf.limit());//9
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=0 lim=9 cap=1024]
            
            //4、利用get()方法读取数据
            byte dst [] = new byte[buf.limit()];
            buf.get(dst);
            System.out.println(new String(dst,0,dst.length));//hello nio
            
            System.out.println(buf.position());//9
            System.out.println(buf.limit());//9
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=9 lim=9 cap=1024]
    }

    关于flip源码:

        public final Buffer flip() {
            limit = position;
            position = 0;
            mark = -1;
            return this;
        }

    实际上是将position的值赋值给limit

    在将position的值置为0

    3、--------------------------------------------------------

        public static void main(String[] args) {
            
            //1、分配一个指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            
            System.out.println(buf.position());//0
            System.out.println(buf.limit());//1024
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=0 lim=1024 cap=1024]
            
            //2、利用put()方法进行存储数据
            String str = "hello nio";
            buf.put(str.getBytes());
            
            System.out.println(buf.position());//9
            System.out.println(buf.limit());//1024
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=9 lim=1024 cap=1024]
            
            //3、切换读取数据的模式
            buf.flip();
            System.out.println(buf.position());//0
            System.out.println(buf.limit());//9
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=0 lim=9 cap=1024]
            
            //4、利用get()方法读取数据
            byte dst [] = new byte[buf.limit()];
            buf.get(dst);
            System.out.println(new String(dst,0,dst.length));//hello nio
            
            System.out.println(buf.position());//9
            System.out.println(buf.limit());//9
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=9 lim=9 cap=1024]
            
            //5、rewind()回到读模式(可重复读数据)
            buf.rewind();
            System.out.println(buf.position());//0
            System.out.println(buf.limit());//9
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=0 lim=9 cap=1024]
        }

    rewind():回到读模式(可重复读取数据)

    相关源码:

        public final Buffer rewind() {
            position = 0;
            mark = -1;
            return this;
        }

    此时是将position的值置为-1

    4、--------------------------------------------------------

    继上述代码继续添加代码:

            //6、清空缓冲区
            buf.clear();
            System.out.println(buf.position());//0
            System.out.println(buf.limit());//1024
            System.out.println(buf.capacity());//1024
            System.out.println(buf.mark());//java.nio.HeapByteBuffer[pos=0 lim=1024 cap=1024]

    清空缓冲区之后将会回到初始化状态

    clear()方法源码:

    将position的值置为0

    将capacity的值赋值给limit

    此将重新进入新创建的缓冲区

        public final Buffer clear() {
            position = 0;
            limit = capacity;
            mark = -1;
            return this;
        }

    缓冲区的数据依然存在,但是处于“被遗忘的数据”(位置界限等都变了)

    5、--------------------------------------------------------

    再次进行添加代码:

            buf.get(dst);
            System.out.println(new String(dst,0,dst.length));//hello nio

    关于标记和重置的使用

        @Test
        public void test(){
            ByteBuffer buf = ByteBuffer.allocate(1024);
            
            String str="abcde";
            buf.put(str.getBytes());
            
            //切换到读取数据模式
            buf.flip();
            
            //读取数据
            byte dst [] = new byte[buf.limit()];
            buf.get(dst,0,2);
            System.out.println("第一次打印操作");
            System.out.println(buf.position());
            System.out.println(new String(dst,0,2));
            
            //进行标记
            buf.mark();
            
            //再次进行读取数据
            buf.get(dst,2,2);
            System.out.println("第二次打印操作");
            System.out.println(buf.position());
            System.out.println(new String(dst,2,2));
            
            //恢复到之前的位置
            buf.reset();
            System.out.println("恢复到第一次操作备份的位置");
            System.out.println(buf.position());
    
        }

    mark()的源码:

        public final Buffer mark() {
            mark = position;
            return this;
        }

    reset()方法源码:

        public final Buffer reset() {
            int m = mark;
            if (m < 0)
                throw new InvalidMarkException();
            position = m;
            return this;
        }

     再次添加新的代码:

            //判断缓冲区是否还有剩余数据
            if(buf.hasRemaining()){
                //获取缓冲区可操作的数据的数量
                System.out.println(buf.remaining());
            }

    hasReaining()方法的源码:

        public final boolean hasRemaining() {
            return position < limit;
        }

    此前有一个恢复到第一次操作数据的位置

    所以此时可以操作的数据剩余量为3

    图解缓冲区的基本属性(position、capacity、limit)

    缓冲区常常使用的方法

  • 相关阅读:
    loj#2049. 「HNOI2016」网络(set 树剖 暴力)
    创建多个Oracle数据库及相应的实例
    [置顶] lua 进阶3--lua文件中调用C++函数
    android 设置Button或者ImageButton的背景透明 半透明 透明
    struts2 18拦截器详解(七)
    《Linux命令行与shell脚本编程大全》 第二十三章 学习笔记
    ios7下不能录音问题解决
    360 2013校园招聘笔试题(含参考答案)
    【MFC三天一个游戏】之 局域网黑白棋
    Remove Nth Node From End of List
  • 原文地址:https://www.cnblogs.com/Mrchengs/p/10817276.html
Copyright © 2011-2022 走看看