java nio读写核心是channel与buffer配合,必须严格遵循四步:写→flip→读→clear/compact;flip将limit设为当前position、position归零以确保正确读取,clear丢弃未读数据,compact保留未读数据并移至开头。

Java NIO 的读写核心就是 Channel 和 Buffer 的配合:数据必须经由 Channel 在 Buffer 中进出,不能绕过 Buffer 直接操作。关键不在于“能不能做”,而在于“怎么切换状态、怎么避免丢数据”。
Buffer 必须按四步走:写 → flip → 读 → clear/compact
Buffer 不是普通数组,它靠 position、limit、capacity 三个指针控制读写边界。刚创建时 position=0、limit=capacity,处于写模式;写完后必须调用 flip() 才能正确读取——它会把 limit 设为当前 position,再把 position 归零,这样读操作才不会越界或跳过数据。
- 写入后未 flip 就直接 get():读不到内容,因为 position 还在末尾,limit 没变
- 读完不 clear 或 compact:下次 write 会覆盖旧数据或抛出异常
- clear 会丢弃所有未读数据,从头开始写;compact 会把未读数据移到开头,保留继续写入的能力(适合部分读完的场景)
Channel 要选对类型,且读写都依赖 Buffer
不同 Channel 用途明确,不能混用:
-
FileChannel:只用于文件,阻塞式,但支持
transferTo/transferFrom零拷贝 - SocketChannel:TCP 客户端通信,可设为非阻塞,需配合 Selector 使用
- ServerSocketChannel:只负责 accept 新连接,生成 SocketChannel
- DatagramChannel:UDP 通信,收发都用 ByteBuffer
所有 Channel 的 read() 和 write() 方法参数都是 Buffer,没有字节数组重载。例如 channel.read(buffer) 是把通道数据填进 buffer,channel.write(buffer) 是把 buffer 里已有的数据发出去。
ByteBuffer 是最常用也最需小心的 Buffer 类型
绝大多数 I/O 场景(文件、网络)都用 ByteBuffer,因为它直接操作字节。创建方式有两种:
-
ByteBuffer.allocate(1024):堆内内存,GC 管理,适合中小量数据 -
ByteBuffer.allocateDirect(1024):堆外内存,减少 JVM 与 OS 间拷贝,适合高频大流量(如网络服务器),但分配/回收成本高
注意:put/get 方法有多种重载(单字节、数组、其他 Buffer),但必须确保 position + 数据长度 ≤ limit,否则抛 BufferOverflowException 或 BufferUnderflowException。
一个典型文件读取循环长这样
以读取文本文件为例,真实代码中需处理编码和异常,但主干逻辑不变:
- 用 RandomAccessFile 或 FileInputStream 获取 FileChannel
- 分配 ByteBuffer,比如 allocate(4096)
- 循环调用
channel.read(buffer),返回值是实际读到的字节数(-1 表示 EOF) - 每次 read 后立即 flip → 读取 → clear(或 compact)→ 继续 read
漏掉 flip 就读不出内容,忘了 clear 就卡在满状态无法继续读——这两个动作不是可选项,是协议级要求。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











