ByteBuffer

NIO,数据的读写操作始终是与缓冲区相关联的.读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区.缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型.ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且信道的读写方法只接收ByteBuffer.因此ByteBuffer的用法是有必要牢固掌握的.

1.创建ByteBuffer
1.1 
使用allocate()静态方法
    ByteBuffer buffer=ByteBuffer.allocate(256);
    
以上方法将创建一个容量为256字节的ByteBuffer,如果发现创建的缓冲区容量太小,唯一的选择就是重新创建一个大小合适的缓冲区.

1.2 
通过包装一个已有的数组来创建
    
如下,通过包装的方法创建的缓冲区保留了被包装数组内保存的数据.
    ByteBuffer buffer=ByteBuffer.wrap(byteArray);

    
如果要将一个字符串存入ByteBuffer,可以如下操作:
    String sendString="
你好,服务器. ";
    ByteBuffer sendBuffer=ByteBuffer.wrap(sendString.getBytes("UTF-16"));

2.
回绕缓冲区
  buffer.flip();
  
这个方法用来将缓冲区准备为数据传出状态,执行以上方法后,输出通道会从数据的开头而不是末尾开始.回绕保持缓冲区中的数据不变,只是准备写入而不是读取.

3.
清除缓冲区
  buffer.clear();
  
这个方法实际上也不会改变缓冲区的数据,而只是简单的重置了缓冲区的主要索引值.不必为了每次读写都创建新的缓冲区,那样做会降低性能.相反,要重用现在的缓冲区,在再次读取之前要清除缓冲区.

4.
从套接字通道(信道)读取数据
  int bytesReaded=socketChannel.read(buffer);
  
执行以上方法后,通道会从socket读取的数据填充此缓冲区,它返回成功读取并存储在缓冲区的字节数.在默认情况下,这至少会读取一个字节,或者返回-1指示数据结束.

5.
向套接字通道(信道)写入数据
  socketChannel.write(buffer);
  
此方法以一个ByteBuffer为参数,试图将该缓冲区中剩余的字节写入信道.

### Java ByteBuffer 的使用方法及示例 #### 1. **ByteBuffer 简介** `ByteBuffer` 是 Java NIO 中的核心类之一,主要用于处理字节数据的缓冲区。通过 `ByteBuffer` 可以实现高效的读写操作,并且能够灵活地在不同模式间切换。 #### 2. **核心概念** `ByteBuffer` 主要依赖三个核心变量来管理其状态: - **position**: 当前正在操作的位置索引。 - **limit**: 缓冲区的有效范围上限。 - **capacity**: 缓冲区的最大容量[^1]。 这些变量共同决定了如何读取或写入数据到缓冲区中。 #### 3. **基本方法** ##### (1) 创建 ByteBuffer 实例 可以通过静态工厂方法创建一个新的 `ByteBuffer` 对象: ```java import java.nio.ByteBuffer; public class Example { public static void main(String[] args) { // 分配一个大小为 10 字节的 ByteBuffer ByteBuffer buffer = ByteBuffer.allocate(10); System.out.println("Capacity: " + buffer.capacity()); } } ``` 上述代码展示了分配固定大小的缓冲区并打印其容量。 ##### (2) 数据写入 可以向 `ByteBuffer` 写入数据,通常会改变 position 的值: ```java buffer.put((byte) 65); // 将单个字节放入缓冲区 buffer.put(new byte[]{66, 67}); // 批量放置多个字节数组 ``` 每次调用 `put()` 方法都会更新 position 值。 ##### (3) 切换至读模式 当完成写入后,需调用 `flip()` 方法准备进入读模式: ```java buffer.flip(); // 设置 limit=position 并重置 position=0 ``` 此时,`limit` 被设为之前的 `position` 值,而 `position` 被重新初始化为 0,以便从头开始读取数据。 ##### (4) 数据读取 可以从 `ByteBuffer` 中提取数据: ```java byte b = buffer.get(); // 获取当前位置的数据并将 position 自增 int size = buffer.remaining(); // 返回剩余可读取的数量 boolean hasRemaining = buffer.hasRemaining(); // 是否还有未读取的内容 ``` 每执行一次 `get()` 操作,`position` 都会被自动增加。 ##### (5) 清理缓冲区 如果希望再次填充新的数据,则应先清理当前缓冲区的状态: ```java buffer.clear(); // 将 position 设回 0,但不修改已有数据 ``` 注意:尽管 `clear()` 方法将 `position` 和其他标志位恢复初始状态,但它并不会清除实际存储的数据内容。 #### 4. **特殊功能** ##### (1) 创建共享子缓冲区 利用 `duplicate()` 或者 `asReadOnlyBuffer()` 方法可以生成原始缓冲区的一个视图副本: ```java ByteBuffer subBuffer = buffer.duplicate(); subBuffer.position(buffer.position()); // 同步位置信息 System.out.println(subBuffer.toString()); // 查看新缓冲区的信息 ``` 这里需要注意的是,两个缓冲区共享同一底层数组资源[^2]。 ##### (2) 访问底层数组偏移量 对于某些特定场景下可能需要用到直接访问内部数组的能力: ```java if (buffer.hasArray()) { // 检查是否有支持数组 int offset = buffer.arrayOffset(); // 获取第一个元素相对于数组起始处的实际距离 System.out.println(offset); } else { throw new UnsupportedOperationException("Direct buffers do not support this operation."); } ``` 该特性仅适用于堆上分配的标准缓冲区实例;如果是直接内存分配则无法获取此类细节[^3]。 ##### (3) 倒带回放机制 有时为了重复利用同一个缓冲区对象而不必频繁重建,可通过如下方式快速回到起点: ```java buffer.rewind(); // 把 position 归零同时保留原有数据不变 ``` 这一步骤非常适合用来多次迭代相同的一批记录集合[^4]。 --- ### 示例综合应用案例 下面给出一段完整的程序演示以上知识点的应用过程: ```java import java.nio.ByteBuffer; import java.util.Arrays; public class ByteBufferExample { public static void main(String[] args) { // 初始化一个长度为8的ByteBuffer ByteBuffer buf = ByteBuffer.allocate(8); // 写入一些测试数据 buf.putInt(123456789); buf.putShort((short) 12345); // 准备读取阶段 buf.flip(); // 提取消息体部分 int valueInt = buf.getInt(); short valueShort = buf.getShort(); System.out.printf("Read Integer=%d, Short=%d%n", valueInt, valueShort); // 展现最终残留情况 System.out.println(Arrays.toString(buf.array())); } } ``` 运行结果将会展示整数与短整形数值及其对应的二进制表现形式。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值