当前位置: 首页 > article >正文

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() 压缩缓冲区

示例

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 中用于文件操作的核心类,可以进行文件的读写和复制。

文件读取示例

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();
        }
    }
}

文件写入示例

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,尤其在高并发的网络通信场景中具有明显优势。

服务器端示例

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();
        }
    }
}

客户端示例

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 的对比

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

六、总结

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


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


http://www.kler.cn/a/419510.html

相关文章:

  • 浪潮X86服务器NF5280、8480、5468、5270使用inter VROC Raid key给NVME磁盘做阵列
  • 如何看linux系统内核是aarch64 ,还是64-bit
  • LeetCode—74. 搜索二维矩阵(中等)
  • Vue.js的核心概念是其强大功能和灵活性的基石
  • 给定一个整数可能为正,0,负数,统计这个数据的位数.
  • sentinel使用手册
  • C 语言学习的经典书籍有哪些?
  • 【数据分析】伊藤公式
  • 【golang】单元测试,以及出现undefined时的解决方案
  • Linux离线安装docker(arm64架构cpu)极速版
  • Python面试实战:高效处理海量日志,找出高频IP
  • 怎么修改虚拟机上Ubuntu的ip为静态ip
  • SpringBoot源码解析(六):打印Banner
  • Brain.js(五):不同的神经网络类型和对比,构建神经网络时该如何选型?
  • 用 Python 从零开始创建神经网络(十三):训练数据集(Training Dataset)
  • ArcGIS对地区进行筛选提取及投影转换
  • Elasticsearch 的存储与查询
  • 数据科学家创建识别假图像的工具
  • 【Go 基础】channel
  • Qt窗口的闪烁QWebEngineView
  • 按vue组件实例类型实现非侵入式国际化多语言翻译
  • 美畅物联丨如何通过 FFmpeg 解码视频
  • STM32 HAL库开发学习5. 系统滴答定时器
  • Linux HTTP代理Squid 基本变更配置及目标白名单方式限制转发
  • Flutter 之 InheritedWidget
  • 【大模型】ChatGPT 提示词优化进阶操作实战详解