天天看点

Java NIO理解之ByteBuffer

作者:宁静知行者

ByteBuffer 是一个字节缓冲区,在java.nio 包,原生NIO 的参数都已经使用ByteBuffer对象,是对byte 数组的封装,通过ByteBuffer API简化对于缓存区字节的操作。

ByteBuffer 可以通过 allacation 方法分配字节内容的空间,或是通过 wrap 方法,将一个字节数组包装成一个ByteBuffer。

类型

ByteBuffer 有两种类型:直接内存、非直接内存类型。

直接内存:DirectByteBuffer, 底层数据是维护在操作系统内存中,不在jvm,只维护引用地址指向数据。通常从外部设备读取时,jvm从这个外部设备的数据读取到一个内存块,再从这个内存块读取。但是使用DirectByteBuffer 不需要从外部设备读取到内存,可以直接读取。

非直接内存:HeapByteBuffer,在jvm堆上维护的一个buffer,底层是一个数组。

数据结构

  1. capacity 缓存区的容量. 该值不允许负值,也不允许修改
  2. opsition下一个可读或可写的位置
  3. limit 缓存区里第一个不能读或不能写的位置,该值不会是负值,同时也不会大于capacity
  4. mark 标志位

几个字段的关系 mark <=position <=limit <=capacity

举例(结合后面的图进行观察变化)

public static void main(String[] args) {
        //1. 分配容量为10 ,默认是 HeapByteBuffer 
        ByteBuffer buffer = ByteBuffer.allocate(10);
      	//ByteBuffer buffer = ByteBuffer.allocateDirect(10);// 创建直接内存缓存
        //2. 写入4个字节
        buffer.put(new byte[]{10, 2, 3, 4});
        System.out.println(String.format("写模式下:pos=%d, limit=%d, capacity=%d", buffer.position(), buffer.limit(), buffer.capacity()));
        System.out.println("切换为读模式");
        //3. 切换为读模式
        buffer.flip();
        System.out.println(String.format("读模式下:pos=%d, limit=%d, capacity=%d", buffer.position(), buffer.limit(), buffer.capacity()));
        System.out.println("读取数据");
        //4. 读取数据
        while (buffer.hasRemaining()) {
            System.out.println(buffer.get());
        }

        System.out.println(String.format("读取数据后:pos=%d, limit=%d, capacity=%d", buffer.position(), buffer.limit(), buffer.capacity()));
        System.out.println("设置pos=1");
        //5. 重新设置pos=1
        buffer.position(1);
        //6. 调用compact 进行数据压缩
        buffer.compact();
        System.out.println(String.format("compact后:pos=%d, limit=%d, capacity=%d", buffer.position(), buffer.limit(), buffer.capacity()));
        while (buffer.hasRemaining()) {
            System.out.println(buffer.get());
        }
        buffer.flip();
        //7. 测试mark & reset
        System.out.println("测试mark&rest 读取一个数据");
        System.out.println(buffer.get());
        System.out.println("mark的pos=" + buffer.position());
        buffer.mark();
        // 读完剩下的内容
        while (buffer.hasRemaining()) {
            System.out.println(buffer.get());
        }
        System.out.println("reset前的pos=" + buffer.position());
        // 重置标识
        buffer.reset();
        System.out.println("reset后的pos=" + buffer.position());
    }           
  • 初始容量
Java NIO理解之ByteBuffer
  • 写入4字节
Java NIO理解之ByteBuffer
  • 切换为读模式(flip)
Java NIO理解之ByteBuffer
  • 读取全部数据
Java NIO理解之ByteBuffer
  • 设置pos =1,数据进行压缩(compact),会切换成写模式
Java NIO理解之ByteBuffer
  • mark & reset

mark 会记录下当下的pos,后面调用reset 可以重置这个pos为mark的值

  • rewind & clear

rewind 会重置 pos = 0,mark =-1,limit不变

clear 会重置pos = 0,limit = capacity, mark = -1,但底层的数组不变,重新写入会覆盖内部数组的数据。

继续阅读