Java NIO:ByteBuffer 与 Channel 的使用
ByteBuffer 是 Java NIO 中用于数据交互的核心容器,而 Channel 则是数据传输的通道。两者的配合是实现高效 I/O 操作的基础。本指南将通过具体步骤,演示如何利用 ByteBuffer 进行数据的读写与传输。
1. 初始化 ByteBuffer
在操作数据之前,必须先分配内存空间。ByteBuffer 提供了两种主要方式来创建实例。
-
调用
ByteBuffer.allocate(int capacity)在 Java 堆中分配指定大小的内存空间。示例代码如下:
ByteBuffer buffer = ByteBuffer.allocate(1024); -
调用
ByteBuffer.wrap(byte[] array)包装一个已有的字节数组。示例代码如下:
byte[] data = "Hello World".getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data);
分配完成后,Buffer 处于初始状态,其核心属性值如下:
| 属性 | 值 | 说明 |
|---|---|---|
| capacity | 1024 | Buffer 的固定容量 |
| position | 0 | 当前读写操作的起始位置,初始为 0 |
| limit | 1024 | 读写的上限,初始状态下等于 capacity |
| mark | -1 | 标记位,默认未设置 |
2. 向 Buffer 写入数据
数据写入通常有两种途径:从 Channel 读取数据写入 Buffer,或者直接通过 put 方法写入。
-
获取一个输入通道(如
FileInputStream获取ReadableByteChannel)。 -
调用
channel.read(buffer)从通道读取数据并存入 Buffer。或者手动写入数据:
buffer.put((byte) 'H'); buffer.put((byte) 'e'); buffer.put((byte) 'l'); buffer.put((byte) 'l'); buffer.put((byte) 'o');
每写入一个字节,position 指针都会向后移动一位。假设写入了 5 个字节,position 将变为 5,而 limit 保持不变。
3. 切换至读模式
Buffer 写满数据或需要读取时,必须调用 flip 方法将 Buffer 从“写状态”切换至“读状态”。
- 调用
buffer.flip()重置指针状态。
此操作会改变 position 和 limit 的值,以便从头读取刚才写入的数据。其内部状态变化逻辑如下:
执行后:
position被重置为 0,表示从头开始读。limit被设置为之前写模式下的position值(即 5),表示只能读取之前写入的数据量。
4. 从 Buffer 读取数据
Buffer 准备就绪后,可以从中读取数据到 Channel,或者直接获取字节数据。
-
获取一个输出通道(如
FileOutputStream获取WritableByteChannel)。 -
调用
channel.write(buffer)将 Buffer 中的数据写入通道。或者通过
get方法逐个读取:byte firstByte = buffer.get(); // 读取第一个字节 'H' byte secondByte = buffer.get(); // 读取第二个字节 'e'
读取过程中,position 会继续向后移动,直到等于 limit,表示数据已读完。
5. 重置与清理 Buffer
读取完毕后,如果想重新利用 Buffer 进行写入,需要根据需求重置 Buffer。
-
调用
buffer.clear()清空缓冲区。此操作将
position置为 0,limit置为capacity。注意:这并未真正删除数据,只是将标记重置,使得下次写入会覆盖原有内容。 -
调用
buffer.compact()压缩缓冲区。如果 Buffer 中还有未读的数据,但需要先写入新数据,使用此方法。它会将未读数据(
position到limit之间)复制到 Buffer 起始处,然后将position移到最后一个未读元素之后。
6. 综合实操:文件复制示例
以下代码演示了从源文件读取数据并写入目标文件的完整流程,涵盖了 allocate、read、flip、write、clear 的标准用法。
- 编写
FileCopyWithNIO类,并填入以下逻辑:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class FileCopyWithNIO {
public static void main(String[] args) throws IOException {
try (FileInputStream fis = new FileInputStream("source.txt");
FileOutputStream fos = new FileOutputStream("dest.txt");
FileChannel sourceChannel = fis.getChannel();
FileChannel destChannel = fos.getChannel()) {
// 1. 分配 Buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (sourceChannel.read(buffer) != -1) {
// 2. 切换至读模式
buffer.flip();
// 3. 写入目标 Channel
destChannel.write(buffer);
// 4. 清空 Buffer,准备下一次读取
buffer.clear();
}
}
}
}
此代码通过循环不断从源通道读取数据到 Buffer,经 flip 切换后写入目标通道,最后通过 clear 重置 Buffer,实现了高效的数据传输。

暂无评论,快来抢沙发吧!