美文网首页
Java NIO之ByteBuffer的介绍和使用

Java NIO之ByteBuffer的介绍和使用

作者: DD_Dog | 来源:发表于2020-06-07 11:53 被阅读0次
    • ByteBuffer类位于java.nio包下,所谓nio:代表new io,另一种解释:N代表Non-blocking IO,非阻塞的IO

    Buffer是一个抽象的基类

    派生类:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer

    Buffer的几个基本属性

    • 基础属性,使用ByteBuffer是以字节Byte为基础的,操作对象是字节
    • capacity--Buffer的容量,读取数据的限制和读取数据的位置,capacity 是分配好的一个内存块大小,分配好后大小不可变
    • limit--在读的模式下,表示缓存内数据的多少,limit<=capacity; 在写的模式下,表示最多能存入多少数据,此时limit=capacity;简单说:在Buffer上进行的读写操作都不能越过这个下标。
    • position--表示读写的位置,下标从0开始

    Buffer的几个方法

    • clear()--position置为0,limit转为capacity大小,标记mark也会被清除
    • flip()--limit被置为当前position的大小,也就是说后续的读操作可能会被限制,这是与clear()有区别的地方;然后position被置为0
    • rewind()--position置为0,标记被取消

    使用举例

    基本用法

    ByteBuffer byteBuffer = ByteBuffer.allocate(10);//分配10个字节大小的缓存 
    byteBuffer.putInt(5);//int占用4个字节
    byteBuffer.put((byte) 1);//1个字节
    byteBuffer.put((byte) 0);//1个字节
    byteBuffer.put("abc".getBytes());//2个字节
    
    System.out.printf("position: %d, limit: %d, capacity: %d\n", buf.position(), buf.limit(), buf.capacity());
    

    打印结果:

    position: 9, limit: 10, capacity: 10
    

    分析:byteBuffer刚开始分配了10个字节的缓存,放入一个Int值5,占用4个字节,两个byte数又占两个,adb占用三个字节,总共占用了9个字节。从打印结果中看到,position为9表示已经存储了9个字节即下标0-8,limit表示在写模式下最多存储10个字节,capacity为10表示缓存容量为10。

    java.nio.BufferOverflowException

    因为ByteBuffer的大小不可变的,所以如果存储的长度超过capacity,那么就会抛出java.nio.BufferOverflowException异常,表示缓冲区上溢出,写入的位置超出了内存长度。

    flip()和clear()

    flip方法的作用是先将limit属性设置为当前的position的值,再将position转为0,并清除标记。
    clear方法的不同之处是limit=capacity。

    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
    byteBuffer.putInt(5);//int占用4个字节
    byteBuffer.put((byte) 1);
    byteBuffer.put((byte) 0);
    byteBuffer.put("abcd".getBytes());
    printByteBuffer(byteBuffer);
    // 读取消息头,因为写完后position已经到10了,所以需要先反转为0,再从头读取
    byteBuffer.flip();//将position置0
    //需要按顺序读取,position自增
    System.out.printf("读取int值: %d\n", byteBuffer.getInt());//读int
    System.out.printf("读取byte值: %d\n", byteBuffer.get());//读byte
    System.out.printf("读取byte值: %d\n", byteBuffer.get());//读byte
    byte[] str = new byte[4];
    byteBuffer.get(str, 0, 4);//连续读4个字节,并保存到str中,注意第二个参数是相对于position的偏移量
    System.out.println("读取字符串=" + new String(str));
    

    打印结果如下:

    position: 10, limit: 10, capacity: 10
    读取int值: 5
    读取byte值: 1
    读取byte值: 0
    读取字符串=abcd
    

    java.nio.BufferUnderflowException

    试一下flip()的使用。上面介绍中提到,flip()的作用是先将limit属性设置为当前的position的值,再将position转为0。也就是说如果当前的position是小于实际保存的字节长度的,那么下次就最多读取到这个position的位置,如果超出则会抛出异常。

    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
    byteBuffer.putInt(5);//int占用4个字节
    byteBuffer.put((byte) 1);
    byteBuffer.put((byte) 0);
    byteBuffer.put("abcd".getBytes());  
    byteBuffer.clear();
    //先读取一个int,再flip()
    System.out.printf("读取int值: %d\n", byteBuffer.getInt());//读int
    byteBuffer.flip();
    System.out.printf("position: %d, limit: %d, capacity: %d\n", byteBuffer.position(), byteBuffer.limit(), byteBuffer.capacity());
    //需要按顺序读取,position自增
    System.out.printf("读取int值: %d\n", byteBuffer.getInt());//读int
    System.out.printf("读取byte值: %d\n", byteBuffer.get());//读byte
    System.out.printf("读取byte值: %d\n", byteBuffer.get());//读byte
    

    打印结果:

    读取int值: 5
    position: 0, limit: 4, capacity: 10
    读取int值: 5
    
    java.nio.BufferUnderflowException
        at java.nio.Buffer.nextGetIndex(Buffer.java:500)
        at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:135)
        at com.heima.ajax.JacksonTest.testByteBuffer(JacksonTest.java:83)
    

    此时报出了内存下溢出的异常,说明读取的位置超出了限制。

    参考

    java.nio.ByteBuffer 以及flip,clear及rewind区别

    相关文章

      网友评论

          本文标题:Java NIO之ByteBuffer的介绍和使用

          本文链接:https://www.haomeiwen.com/subject/cltctktx.html