一、ByteBuffer 概述
- ByteBuffer 是 Java NIO 中用于高效处理二进制数据的类,它提供了比传统 IO 更灵活的数据操作方式,它有如下特点
-
固定容量:创建时指定大小,不可动态扩展
-
双指针机制:通过 position 和 limit 控制读写位置
-
直接内存支持:可分配堆外内存减少拷贝开销
-
视图缓冲:可生成只读、读写视图
-
字节序控制:支持大端和小端
二、创建 ByteBuffer
1、基本介绍
- 堆内存分配
static ByteBuffer allocate(int capacity)
- 直接内存分配
static ByteBuffer allocateDirect(int capacity)
- 包装现有数组
static ByteBuffer wrap(byte[] array)
- 包装数组子范围
static ByteBuffer wrap(byte[] array, int offset, int length)
2、演示
- 堆内存分配,分配 100 字节的堆内存缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
- 直接内存分配,分配 100 字节的直接内存缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(100);
- 包装现有数组
byte[] byteArray = new byte[100];
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
- 包装数组子范围,偏移 10,长度 50
byte[] byteArray = new byte[100];
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray, 10, 50);
3、堆内存缓冲区与直接内存缓冲区
特性 | 堆内存缓冲区 | 直接内存缓冲区 |
---|---|---|
内存位置 | JVM 堆内存 | 堆外内存 |
分配速度 | 较快 | 较慢 |
IO 效率 | 需要拷贝 | 零拷贝 |
垃圾回收 | 通过 GC 管理 | 通过 Cleaner 机制回收 |
适用场景 | 短期使用、小数据量 | 长期使用、大数据量、高频IO |
三、基础读写操作
1、基本介绍
- 读取数据
ByteBuffer put(byte b)
- 写入数据
byte get()
2、演示
- 读取数据
ByteBuffer byteBuffer = ByteBuffer.wrap("Hello World".getBytes());
while (byteBuffer.hasRemaining()) {
System.out.println((char) byteBuffer.get());
}
# 输出结果
H
e
l
l
o
- 写入数据
ByteBuffer byteBuffer = ByteBuffer.wrap("Hello World".getBytes());
while (byteBuffer.hasRemaining()) {
System.out.println((char) byteBuffer.get());
}
# 输出结果
H
e
l
l
o
W
o
r
l
d
四、核心属性与模式切换
1、基本介绍
- 核心属性
属性 | 获取方法 | 说明 |
---|---|---|
capacity | int capacity() | 缓冲区总容量,创建后不可变 |
position | int position() | 下一个要读写的位置,初始为 0 |
limit | int limit() | 可读写数据的终点位置,初始等于 capacity |
mark | 无直接获取方法 | 标记位置,可通过 reset 方法返回到此位置 |
- 模式切换方法
方法 | 作用 |
---|---|
ByteBuffer flip() | 写切换到读模式:limit = position, position = 0 |
clear | 读切换到写模式:limit = capacity, position=0 |
rewind | 重读:position = 0,不改变 limit |
compact | 压缩:将未读数据移到开头,position = 剩余数据量 |
2、演示
- flip 方法
ByteBuffer buf = ByteBuffer.allocate(10);
buf.put("abc".getBytes());
System.out.println("写模式: pos=" + buf.position() + ", limit=" + buf.limit());
buf.flip();
System.out.println("读模式: pos=" + buf.position() + ", limit=" + buf.limit());
# 输出结果
写模式: pos=3, limit=10
读模式: pos=0, limit=3
- clear 方法
ByteBuffer buf = ByteBuffer.allocate(10);
buf.put("abc".getBytes());
System.out.println("写模式: pos=" + buf.position() + ", limit=" + buf.limit());
buf.flip();
System.out.println("读模式: pos=" + buf.position() + ", limit=" + buf.limit());
buf.clear();
System.out.println("写模式: pos=" + buf.position() + ", limit=" + buf.limit());
# 输出结果
写模式: pos=3, limit=10
读模式: pos=0, limit=3
写模式: pos=0, limit=10
- rewind 方法
ByteBuffer buf = ByteBuffer.allocate(10);
buf.put("xyz".getBytes());
buf.flip();
System.out.println("第一次读取: " + (char) buf.get());
System.out.println("当前 pos: " + buf.position());
buf.rewind();
System.out.println("重读: " + (char) buf.get());
System.out.println("当前 pos: " + buf.position());
# 输出结果
第一次读取: x
当前 pos: 1
重读: x
当前 pos: 1
- compact 方法
ByteBuffer buf = ByteBuffer.allocate(10);
buf.put("123456".getBytes());
buf.flip();
System.out.println("读取数据: " + (char) buf.get());
System.out.println("未读数据: " + (char) buf.get());
System.out.println("压缩前: pos=" + buf.position() + ", 剩余数据=" + buf.remaining());
buf.compact();
System.out.println("压缩后: pos=" + buf.position() + ", 剩余空间=" + buf.remaining());
# 输出结果
读取数据: 1
未读数据: 2
压缩前: pos=2, 剩余数据=4
压缩后: pos=4, 剩余空间=6
- mark 方法与 reset 方法
ByteBuffer buf = ByteBuffer.allocate(10);
buf.put("123456".getBytes());
buf.flip();
System.out.println("读取数据: " + (char) buf.get());
System.out.println("未读数据: " + (char) buf.get());
buf.mark();
System.out.println("读取数据: " + (char) buf.get());
System.out.println("未读数据: " + (char) buf.get());
buf.reset();
System.out.println("重置后");
System.out.println("读取数据: " + (char) buf.get());
System.out.println("未读数据: " + (char) buf.get());
# 输出结果
读取数据: 1
未读数据: 2
读取数据: 3
未读数据: 4
重置后
读取数据: 3
未读数据: 4