Java NIO 全面详解:初学者入门指南

除了前一篇文章讲的传统的 java.io 模块,Java 还提供了更现代化、更高效的非阻塞 IO 模块,即 java.nio(New IO)java.nio 引入了面向缓冲区(Buffer)的数据处理方式,以及多路复用器(Selector)实现的非阻塞通信模型。下面将详细讲解 java.nio 相关知识,帮助你全面了解 Java 的 IO 体系。


一、什么是 NIO?

NIO(New Input/Output)是 Java 1.4 引入的 IO 框架,旨在解决传统 IO 模块性能不足的问题,特别是针对高并发和大数据量的场景。

NIO 的特点包括:

  1. 非阻塞模式:通过多路复用器(Selector),可以在单线程中管理多个通道(Channel)。
  2. 基于缓冲区(Buffer):数据读写操作基于缓冲区,而非直接操作流。
  3. 内存映射文件(Memory-Mapped File):高效地处理大文件。

二、NIO 的核心概念

NIO 的设计思想与传统 IO 有显著区别,主要围绕以下几个核心组件:

2.1 Channel(通道)

通道是 NIO 的核心接口,用于读写数据,类似于传统 IO 中的流。常见通道包括:

  • FileChannel:用于文件数据的读写。
  • SocketChannel:用于网络数据的读写。
  • ServerSocketChannel:用于服务器端的网络数据处理。

特点

  • 双向性:同一个通道可以同时进行读和写。
  • 非阻塞性:支持异步操作。

2.2 Buffer(缓冲区)

缓冲区是数据的容器,负责存储读写数据。所有的通道读写操作都要通过缓冲区完成。

常见缓冲区类型:

  • ByteBuffer:存储字节数据。
  • CharBuffer:存储字符数据。
  • IntBuffer、FloatBuffer 等:存储特定类型的基本数据。

缓冲区的核心属性

  • capacity:缓冲区的总容量,不能改变。
  • position:当前操作的位置指针。
  • limit:当前可操作数据的上限。
  • mark:一个临时记录的指针位置。

Buffer 的基本操作流程

  1. 写入数据到缓冲区
  2. 调用 flip() 切换为读模式
  3. 读取数据
  4. 调用 clear() 清空缓冲区compact() 压缩缓冲区

示例

java 复制代码
import java.nio.ByteBuffer;

public class BufferExample {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配容量为 1024 的缓冲区

        // 写数据到缓冲区
        String data = "Hello, NIO!";
        buffer.put(data.getBytes());

        // 切换到读模式
        buffer.flip();

        // 读取缓冲区中的数据
        byte[] readData = new byte[buffer.remaining()];
        buffer.get(readData);
        System.out.println(new String(readData));

        // 清空缓冲区
        buffer.clear();
    }
}

2.3 Selector(选择器)

选择器是 NIO 实现多路复用的核心组件,可以同时监控多个通道的状态(如是否可读、可写、连接就绪等)。

Selector 的工作流程

  1. 将通道注册到选择器,并指定关注的事件(如 OP_READ)。
  2. 调用选择器的 select() 方法检测通道是否有事件发生。
  3. 获取就绪的通道并进行操作。

三、FileChannel 示例

FileChannel 是 NIO 中用于文件操作的核心类,可以进行文件的读写和复制。

文件读取示例

java 复制代码
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileChannelExample {
    public static void main(String[] args) {
        try (RandomAccessFile file = new RandomAccessFile("example.txt", "r");
             FileChannel channel = file.getChannel()) {

            // 创建缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            // 读取数据到缓冲区
            int bytesRead = channel.read(buffer);
            while (bytesRead != -1) {
                buffer.flip(); // 切换为读模式

                while (buffer.hasRemaining()) {
                    System.out.print((char) buffer.get());
                }

                buffer.clear(); // 清空缓冲区
                bytesRead = channel.read(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

文件写入示例

java 复制代码
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileChannelExample {
    public static void main(String[] args) {
        try (RandomAccessFile file = new RandomAccessFile("example.txt", "rw");
             FileChannel channel = file.getChannel()) {

            String data = "Hello, FileChannel!";
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            buffer.put(data.getBytes());
            buffer.flip(); // 切换为读模式,准备写入通道

            channel.write(buffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

四、NIO 的非阻塞通信示例

NIO 的最大优势是支持非阻塞 IO,尤其在高并发的网络通信场景中具有明显优势。

服务器端示例

java 复制代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class NIOServer {
    public static void main(String[] args) {
        try (ServerSocketChannel serverChannel = ServerSocketChannel.open()) {
            serverChannel.bind(new InetSocketAddress(8080));
            serverChannel.configureBlocking(false); // 非阻塞模式

            System.out.println("服务器启动,等待连接...");

            while (true) {
                SocketChannel clientChannel = serverChannel.accept();
                if (clientChannel != null) {
                    System.out.println("客户端连接成功!");
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    buffer.put("Hello, Client!".getBytes());
                    buffer.flip();
                    clientChannel.write(buffer);
                    clientChannel.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端示例

java 复制代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NIOClient {
    public static void main(String[] args) {
        try (SocketChannel clientChannel = SocketChannel.open()) {
            clientChannel.connect(new InetSocketAddress("localhost", 8080));

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            clientChannel.read(buffer);

            buffer.flip();
            System.out.println("收到服务器消息:" + new String(buffer.array(), 0, buffer.limit()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

五、NIO 与 IO 的对比

特性 传统 IO NIO
数据处理单位 流(Stream) 缓冲区(Buffer)
阻塞模式 阻塞 非阻塞
多路复用 不支持 支持(通过 Selector)
性能 相对较低 更适合高并发场景
操作复杂性 简单 相对复杂

六、总结

java.nio 提供了更高效和灵活的 IO 操作方式,适用于需要高性能和高并发的场景。它通过非阻塞模型和缓冲区机制解决了传统 IO 的许多性能瓶颈。但对于简单的文件操作场景,传统 IO 更加直观和易用。


如果你对 java.nio 感兴趣,可以深入学习 Selector 的使用以及结合线程池的高效处理方案。希望这篇文章对你有所帮助,欢迎在评论区交流你的学习心得!

相关推荐
阿里嘎多学长34 分钟前
2026-04-30 GitHub 热点项目精选
开发语言·程序员·github·代码托管
abcnull2 小时前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
叶小鸡2 小时前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
juniperhan3 小时前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_180079054733 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
c++之路3 小时前
C++23概述
java·c++·c++23
时空系3 小时前
第10篇:继承扩展——面向对象编程进阶 python中文编程
开发语言·python·ai编程
专注API从业者4 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
CHANG_THE_WORLD4 小时前
python 批量终止进程exe
开发语言·python