文章目录

Java NIO:ByteBuffer 与 Channel 的使用

发布于 2026-04-12 08:26:02 · 浏览 7 次 · 评论 0 条

Java NIO:ByteBuffer 与 Channel 的使用

ByteBuffer 是 Java NIO 中用于数据交互的核心容器,而 Channel 则是数据传输的通道。两者的配合是实现高效 I/O 操作的基础。本指南将通过具体步骤,演示如何利用 ByteBuffer 进行数据的读写与传输。


1. 初始化 ByteBuffer

在操作数据之前,必须先分配内存空间。ByteBuffer 提供了两种主要方式来创建实例。

  1. 调用 ByteBuffer.allocate(int capacity) Java 堆中分配指定大小的内存空间。

    示例代码如下:

    ByteBuffer buffer = ByteBuffer.allocate(1024);
  2. 调用 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 方法写入。

  1. 获取一个输入通道(如 FileInputStream 获取 ReadableByteChannel)。

  2. 调用 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 从“写状态”切换至“读状态”。

  1. 调用 buffer.flip() 重置指针状态。

此操作会改变 positionlimit 的值,以便从头读取刚才写入的数据。其内部状态变化逻辑如下:

graph LR A[\"写状态结束\nposition=5, limit=1024\"] -->|调用 flip| B B --> C[\"读状态就绪\nposition=0, limit=5\"]

执行后:

  • position 被重置为 0,表示从头开始读。
  • limit 被设置为之前写模式下的 position 值(即 5),表示只能读取之前写入的数据量。

4. 从 Buffer 读取数据

Buffer 准备就绪后,可以从中读取数据到 Channel,或者直接获取字节数据。

  1. 获取一个输出通道(如 FileOutputStream 获取 WritableByteChannel)。

  2. 调用 channel.write(buffer) Buffer 中的数据写入通道。

    或者通过 get 方法逐个读取:

    byte firstByte = buffer.get(); // 读取第一个字节 'H'
    byte secondByte = buffer.get(); // 读取第二个字节 'e'

读取过程中,position 会继续向后移动,直到等于 limit,表示数据已读完。


5. 重置与清理 Buffer

读取完毕后,如果想重新利用 Buffer 进行写入,需要根据需求重置 Buffer。

  1. 调用 buffer.clear() 清空缓冲区。

    此操作将 position 置为 0,limit 置为 capacity注意:这并未真正删除数据,只是将标记重置,使得下次写入会覆盖原有内容。

  2. 调用 buffer.compact() 压缩缓冲区。

    如果 Buffer 中还有未读的数据,但需要先写入新数据,使用此方法。它会将未读数据(positionlimit 之间)复制到 Buffer 起始处,然后将 position 移到最后一个未读元素之后。


6. 综合实操:文件复制示例

以下代码演示了从源文件读取数据并写入目标文件的完整流程,涵盖了 allocatereadflipwriteclear 的标准用法。

  1. 编写 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,实现了高效的数据传输。

评论 (0)

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

扫一扫,手机查看

扫描上方二维码,在手机上查看本文