Java-IO、NIO

Java IO 和 NIO 介绍

Java 提供了两种主要的 I/O 模型:IO(Blocking I/O)NIO(Non-blocking I/O)。它们分别适用于不同的场景,理解它们的区别和使用方法对于编写高效的 Java 程序非常重要。


一、Java IO(Blocking I/O)

1. 特点

  • 阻塞式:当线程执行读/写操作时,如果数据没有准备好,线程会一直阻塞,直到数据就绪。
  • 流式模型:基于流(Stream)的 I/O,数据像水流一样单向流动。
  • 面向字节/字符
    • 字节流InputStreamOutputStream
    • 字符流ReaderWriter

2. 核心类

  • 字节流
    • FileInputStream / FileOutputStream:文件读写。
    • BufferedInputStream / BufferedOutputStream:带缓冲区的字节流。
  • 字符流
    • FileReader / FileWriter:文件读写。
    • BufferedReader / BufferedWriter:带缓冲区的字符流。

3. 示例

// 使用字节流读取文件
try (FileInputStream fis = new FileInputStream("input.txt");
     BufferedInputStream bis = new BufferedInputStream(fis)) {
    int data;
    while ((data = bis.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

// 使用字符流读取文件
try (FileReader fr = new FileReader("input.txt");
     BufferedReader br = new BufferedReader(fr)) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

4. 适用场景

  • 简单的文件读写。
  • 数据量较小、并发要求不高的场景。

二、Java NIO(Non-blocking I/O)

1. 特点

  • 非阻塞式:线程在读写数据时不会被阻塞,可以处理其他任务。
  • 缓冲区模型:数据先读写到缓冲区(Buffer),再进行处理。
  • 通道(Channel):用于连接数据源和目标,支持双向读写。
  • 选择器(Selector):用于监听多个通道的事件(如连接、读写)。

2. 核心类

  • Buffer
    • ByteBufferCharBufferIntBuffer 等。
  • Channel
    • FileChannel:文件读写。
    • SocketChannelServerSocketChannel:网络通信。
    • DatagramChannel:UDP 通信。
  • Selector
    • 用于监听多个通道的事件。

3. 示例

// 使用 NIO 读取文件
try (FileChannel channel = FileChannel.open(Paths.get("input.txt"))) {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    while (channel.read(buffer) != -1) {
        buffer.flip(); // 切换为读模式
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear(); // 清空缓冲区,准备下一次读取
    }
} catch (IOException e) {
    e.printStackTrace();
}

// 使用 NIO 实现非阻塞网络通信
try (Selector selector = Selector.open();
     ServerSocketChannel serverChannel = ServerSocketChannel.open()) {
    serverChannel.bind(new InetSocketAddress(8080));
    serverChannel.configureBlocking(false);
    serverChannel.register(selector, SelectionKey.OP_ACCEPT);

    while (true) {
        selector.select();
        Set<SelectionKey> keys = selector.selectedKeys();
        Iterator<SelectionKey> iter = keys.iterator();
        while (iter.hasNext()) {
            SelectionKey key = iter.next();
            if (key.isAcceptable()) {
                // 处理连接事件
                SocketChannel clientChannel = serverChannel.accept();
                clientChannel.configureBlocking(false);
                clientChannel.register(selector, SelectionKey.OP_READ);
            } else if (key.isReadable()) {
                // 处理读事件
                SocketChannel clientChannel = (SocketChannel) key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                clientChannel.read(buffer);
                buffer.flip();
                System.out.println(new String(buffer.array(), 0, buffer.limit()));
                buffer.clear();
            }
            iter.remove();
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

4. 适用场景

  • 高并发、高吞吐量的网络通信。
  • 需要非阻塞 I/O 的场景(如聊天服务器、文件服务器)。

三、Java IO 和 NIO 的区别

特性 Java IO Java NIO
模型 阻塞式 非阻塞式
数据流 单向流(Stream) 双向通道(Channel)
缓冲区 无缓冲区 基于缓冲区(Buffer)
多路复用 不支持 支持(Selector)
适用场景 简单文件读写、低并发场景 高并发、高吞吐量场景

四、Java NIO 的高级特性

1. 内存映射文件(Memory-Mapped File)

  • 将文件直接映射到内存中,避免频繁的系统调用。
  • 示例:
    try (FileChannel channel = FileChannel.open(Paths.get("input.txt"))) {
        MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    

2. 分散(Scatter)和聚集(Gather)

  • 分散:从单个通道读取数据到多个缓冲区。
  • 聚集:将多个缓冲区的数据写入单个通道。
  • 示例:
    ByteBuffer header = ByteBuffer.allocate(128);
    ByteBuffer body = ByteBuffer.allocate(1024);
    ByteBuffer[] buffers = {header, body};
    
    try (FileChannel channel = FileChannel.open(Paths.get("input.txt"))) {
        channel.read(buffers); // 分散读取
    } catch (IOException e) {
        e.printStackTrace();
    }
    

3. 文件锁(File Lock)

  • 控制多个进程对同一文件的并发访问。
  • 示例:
    try (FileChannel channel = FileChannel.open(Paths.get("input.txt"), StandardOpenOption.WRITE)) {
        FileLock lock = channel.lock(); // 获取文件锁
        // 执行写操作
        lock.release(); // 释放文件锁
    } catch (IOException e) {
        e.printStackTrace();
    }
    

五、总结

  • Java IO
    • 适用于简单的文件读写和低并发场景。
    • 基于流模型,操作简单但性能较低。
  • Java NIO
    • 适用于高并发、高吞吐量的场景。
    • 基于缓冲区和通道模型,支持非阻塞 I/O 和多路复用。

根据实际需求选择合适的 I/O 模型:

  • 如果需要处理高并发网络通信,选择 NIO
  • 如果只是简单的文件读写,选择 IO 即可。

通过掌握 Java IO 和 NIO 的使用方法,可以更好地应对不同的 I/O 需求,编写高效的 Java 程序。

posted @   shog808  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2022-02-21 Java中的泛型
2020-02-21 shell脚本自动化部署
点击右上角即可分享
微信分享提示