Java ByteBuffer用法

本文介绍了Java中的ByteBuffer,重点讲解其属性如position、limit、capacity和mark的含义,以及allocate、wrap、put、get、flip、compact、mark和reset等关键函数的用法。在非阻塞IO中,ByteBuffer在读取流数据时的角色被强调,特别是clear、flip和rewind操作对数据处理的影响。还讨论了如何处理不完整或包含多个数据包的情况,并建议参考JDK API文档深入理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ByteBuffer的常用属性

1.position 标识下一个byte的操作位

2.limit 标识上界

3.capacity 标识容量

4.mark 辅助标识

 

ByteBuffer的常用函数

 

ByteBuffer.allocate(250) -- 新建byteBuffer

bb.wrap(new byte[100]) -- 新建byteBuffer

 

put方法写 -- 入缓冲区

get方法  -- 读取缓冲区

 

flip方法 反转 -- 用于从写入到读取的操作,将position为0,limit为原position

 

compact方法 --  压缩,舍弃position之前的内容

 

mark()  --  标志position

reset() --  重新设置position为当初的mark值


对于ByteBuffer主要需要注意的是几个标志的含义:position,limit,capability,mark.几个操作的影响:flip(),clear(),rewind().还有就是在读取或者写入时,标志的变化,比如get()方法导致position加1.

SocketChannel采用的是非阻塞异步读取流数据,在读取的时候,通常是

 
  1. ByteBuffer.clear();
  2. SocketChannel.read(ByteBuffer);

如果流中有数据,就会把数据从position开始读到ByteBuffer中,在读取之前ByteBuffer的clear操作会把position置为0,limit置为capability,也就是相当于清空了之前的内容,但是ByteBuffer中数组的内容在read之前是没有改变的.

read之后,通常就是开始从ByteBuffer中提取读到的数据,如果你的数据是以自己定义的数据包的格式进行发送的,那你还需要判断是否读到了数据包的结尾,因为对流数据本身来说是没有结尾这一说的。在提取数据之前,要先把position放到开始读取时的位置,把limit放到当前位置,所以要flip一下,表示从position到limit的位置都是需要的数据。

 
  1. ByteBuffer.flip();
  2. while(ByteBuffer.hasRemaining()){
  3. byte c=ByteBuffer.get();
  4. if (b == PACKAGE_END) {
  5. //you can return the package here
  6. }else{
  7. //you can append the byte here.like StringBuilder.append().
  8. }
  9. }

这样以来也存在一个问题,当一次读到的ByteBuffer不包含完整的数据包或者包含多个数据包.那么就需要在下一次继续把这些包分拆出来.那么在读取数据的代码处就可以改为,这样就把之前读取到的未完整的包保留了下来:

 
  1. if(!ByteBuffer.hasRemaining){
  2. ByteBuffer.clear();
  3. SocketChannel.read(ByteBuffer);
  4. }

另外一个可能会用到的操作就是ByteBuffer.rewind(),他会把position置为0,limit保持不变,可以用于重复读取一段数据.

ByteBuffer是nio中一个非常方便的工具.设计思想也非常值得借鉴.


一手文档可以参考jdk api doc中的 java.nio.Buffer java.nio.ByteBuffer


### JavaByteBuffer类的使用方法 #### 创建ByteBuffer对象 可以通过静态工厂方法`allocate()`创建指定容量大小的ByteBuffer实例。此方式适用于堆内内存分配。 ```java int size = 1024; ByteBuffer buffer = ByteBuffer.allocate(size); ``` 对于直接缓冲区,则可以调用`allocateDirect(int capacity)`来获取,该种类型的缓冲区通常具有更好的性能,特别是在执行通道读写操作时[^1]。 #### 基本属性设置与访问 - `position()`: 返回当前位置;可修改位置以便于后续的数据存取。 - `limit()`: 获取当前界限值;调整界限用于限定有效数据范围。 - `capacity()`: 获得总容量,即最大能容纳多少字节数量。 这些状态变量满足关系:mark <= position <= limit <= capacity[^4]。 #### 数据填充与检索 向ByteBuffer写入数据前需先设定其为写模式(`clear()`或`flip()`之后),完成写入后再切换到读模式准备取出数据: ```java // 向buffer中放入byte数组data的内容 byte[] data = "HelloWorld".getBytes(StandardCharsets.UTF_8); buffer.put(data); // 切换成读模式 buffer.flip(); while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } ``` 当全部内容被消费完毕后应当重置缓冲器的状态以备下次循环利用,这可通过调用`compact()`实现部分保留未读过的剩余数据并释放已读过区域的空间,或者通过`clear()`完全清空整个缓存空间等待下一轮输入[^3]。 #### 文件I/O和网络传输应用案例 在实际项目开发过程中,经常遇到需要将文件映射成内存视图的情况,这时就可以借助FileChannel配合MappedByteBuffer来进行高效的随机访问读写了。另外在网络编程里,ServerSocketChannel搭配SelectionKey能够很好地支持非阻塞多路复用模型下的并发处理机制[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值