一文详解java.nio.ByteBuffer

java.nio.ByteBuffer是一个可以进行缓冲区分配读取写入的缓冲区,其持有一个字节数组,并通过4个属性:capacitylimitpositionmark来管理缓冲区,进行字节级别读取和数据写入。基于此,ByteBuffer常被用来处理网络协议和I/O操作。

一、使用举例

以下为ByteBuffer的使用举例:

  • 可以使用put()方法将数据写入缓冲区;
  • 可以使用flip()方法切换缓冲区为读取模式;
  • 可以使用rewind()方法倒回缓冲区的初始位置;
  • 可以使用get()方法读取缓冲区中的数据;
  • 可以使用clear()方法清空缓冲区,以便再次写入数据。
import java.nio.ByteBuffer;

public class JavaTest {
    
    
    public static void main(String[] args)
    {
    
    
        System.out.println("~~~~~~~~ put(byte b) ~~~~~~~~");
        // 分配一个5字节的buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(5);
        // 向buffer中添加两个字节的数据,空余3个字节数据
        byteBuffer.put((byte)10);
        byteBuffer.put((byte)20);
        // 输出整个字节数组
        printByteBuffer(byteBuffer);
        System.out.println("~~~~~~~~ flip() ~~~~~~~~");
        // 转为读模式
        byteBuffer.flip();
        // 输出整个字节数组
        printByteBuffer(byteBuffer);
        System.out.println("~~~~~~~~ get() ~~~~~~~~");
        // 读取当前 position 
        System.out.println(byteBuffer.get());
        // 输出整个字节数组
        printByteBuffer(byteBuffer);
        System.out.println("~~~~~~~~ rewind() ~~~~~~~~");
        // 倒回缓冲区的初始位置
        byteBuffer.rewind();
        printByteBuffer(byteBuffer);
        System.out.println("~~~~~~~~ get(byte[] dst, int offset, int length) ~~~~~~~~");
        // 将buffer中数据写入到dstBytes中
        byte[] dstBytes = new byte[2];
        byteBuffer.get(dstBytes, 0, dstBytes.length);
        printByteBuffer(byteBuffer);
        
    }
    
    public static void printByteBuffer(ByteBuffer byteBuffer) {
    
    
        byte[] bytes = byteBuffer.array();
        int position = byteBuffer.position();
        int limit = byteBuffer.limit();
        int remining = byteBuffer.remaining();
        System.out.println("byteBuffer: "
                + Arrays.toString(bytes)
                + "\nPosition: " + position
                + " Limit: " + limit
                + " Remining: " + remining);
    }
}

控制台输出如下:

~~~~~~~~ put(byte b) ~~~~~~~~
byteBuffer: [10, 20, 0, 0, 0]
Position: 2 Limit: 5 Remining: 3
~~~~~~~~ flip() ~~~~~~~~
byteBuffer: [10, 20, 0, 0, 0]
Position: 0 Limit: 2 Remining: 2
~~~~~~~~ get() ~~~~~~~~
10
byteBuffer: [10, 20, 0, 0, 0]
Position: 1 Limit: 2 Remining: 1
~~~~~~~~ rewind() ~~~~~~~~
byteBuffer: [10, 20, 0, 0, 0]
Position: 0 Limit: 2 Remining: 2
~~~~~~~~ get(byte[] dst, int offset, int length) ~~~~~~~~
byteBuffer: [10, 20, 0, 0, 0]
Position: 2 Limit: 2 Remining: 0

二、原理简析

前边说过ByteBuffer持有一个字节数组,并通过4个属性:capacity、limit、position、mark来管理缓冲区,这4个属性遵循mark <= position <= limit <= capacity,下表格是对着4个属性的解释:

属性 描述
Capacity 容量,即可以容纳的最大数据量
Limit 缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作
Position 下一个要被读或写的元素的索引
Mark 标记。可调用mark()设置标记(mark=position),然后调用reset()让position恢复到标记的位置

初始化,各控制属性状态:
例如调用ByteBuffer byteBuffer = ByteBuffer.allocate(5);进行ByteBuffer存储空间分配,各属性见下图所示:

ByteBuffer初始状态各控制属性

写入数据后,各控制控制属性状态:
例如调用byteBuffer.put((byte)'a')写入数据后,各属性见下图所示:
写入数据后,各控制控制属性状态

读取数据后,各控制控制属性状态:
例如调用byteBuffer.get()读取4个字节后,各属性见下图所示:
读取数据后,各控制控制属性状态

猜你喜欢

转载自blog.csdn.net/aiwusheng/article/details/129039900
今日推荐