zoukankan      html  css  js  c++  java
  • NIO之缓冲区(Buffer)的数据存取

    缓冲区(Buffer)

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

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

      Buffer就像一个数组,可以保存多个相同类型的数据。根据类型不同(boolean除外),有以下Buffer常用子类:

    1. ByteBuffer
    2. CharBuffer
    3. ShortBuffer
    4. IntBuffer
    5. LongBuffer
    6. FloatBuffer
    7. 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。

    java.nio.Buffer.java
     View Code

     注意: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相等
    --------------------------------
  • 相关阅读:
    JS操作JSON总结
    jQuery对select操作
    MS SQL GUID
    QT延时方法
    MySQL 实践
    MySQL 入门教程
    asp.net获取URL和IP地址
    C#-foreach与yield
    C#—序列化(Serialize)和反序列化(NonSerialize)
    Newtonsoft.Json序列化和反序列
  • 原文地址:https://www.cnblogs.com/shamo89/p/9612789.html
Copyright © 2011-2022 走看看