Java IO和NIO的基本概念和API详解

 更新时间:2025年03月11日 16:33:49   作者:冰糖心书房  
JavaIO是基于流的阻塞式I/O,适用于低并发场景;JavaNIO是基于通道和缓冲区的非阻塞式I/O,适用于高并发场景

一、 Java IO (Blocking IO)

基本概念

  • Java IO 是 Java 平台提供的用于进行输入和输出操作的 API。
  • Java IO 基于 流 (Stream) 的模型,数据像水流一样从一个地方流向另一个地方。
  • Java IO 主要是 阻塞式 I/O (Blocking I/O),即线程在执行 I/O 操作时会被阻塞,直到操作完成。
  • 传统IO指的是java.io包下的部分组件(File, InputStream, OutputStream, Reader, Writer)。

IO 流的分类

按数据传输方向:

  • 输入流 (Input Stream): 用于从数据源读取数据(例如,从文件、网络连接、键盘等)。 以 InputStreamReader 作为基类。
  • 输出流 (Output Stream): 用于将数据写入到目标(例如,写入到文件、网络连接、控制台等)。 以 OutputStreamWriter 作为基类。

按数据传输单位:

  • 字节流 (Byte Stream): 以字节 (8 bits) 为单位进行数据传输。 以 InputStreamOutputStream 作为基类。 适用于处理二进制数据(例如,图片、音频、视频等)。
  • 字符流 (Character Stream): 以字符 (16 bits) 为单位进行数据传输。 以 ReaderWriter 作为基类。 适用于处理文本数据。

核心类和接口

InputStream (字节输入流):

  • FileInputStream: 从文件中读取字节。
  • ByteArrayInputStream: 从字节数组中读取字节。
  • ObjectInputStream: 从对象流中读取对象。
  • BufferedInputStream: 带缓冲的字节输入流,提高读取效率。

OutputStream (字节输出流):

  • FileOutputStream: 向文件中写入字节。
  • ByteArrayOutputStream: 向字节数组中写入字节。
  • ObjectOutputStream: 向对象流中写入对象。
  • BufferedOutputStream: 带缓冲的字节输出流,提高写入效率。

Reader (字符输入流):

  • FileReader: 从文件中读取字符。
  • CharArrayReader: 从字符数组中读取字符。
  • BufferedReader: 带缓冲的字符输入流,提高读取效率。
  • InputStreamReader: 将字节输入流转换为字符输入流(需要指定字符编码)。

Writer (字符输出流):

  • FileWriter: 向文件中写入字符。
  • CharArrayWriter: 向字符数组中写入字符。
  • BufferedWriter: 带缓冲的字符输出流,提高写入效率。
  • OutputStreamWriter: 将字节输出流转换为字符输出流(需要指定字符编码)。
  • File: 表示文件或目录的抽象表示。

IO 操作流程 (以读取文件为例)

  1. 创建 File 对象: 指定要读取的文件路径。
  2. 创建 FileInputStream 对象:File 对象作为参数传递给 FileInputStream 的构造方法,创建一个 FileInputStream 对象。
  3. 创建 BufferedInputStream 对象 (可选):FileInputStream 对象作为参数传递给 BufferedInputStream 的构造方法,创建一个 BufferedInputStream 对象,提高读取效率。
  4. 读取数据: 使用 read() 方法从输入流中读取数据。
  5. 关闭流: 在完成读取操作后,务必关闭输入流,释放资源(先关闭 BufferedInputStream,再关闭 FileInputStream)。

代码示例 (读取文件内容):

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class IOExample {
    public static void main(String[] args) {
        File file = new File("test.txt"); // 替换为你的文件路径

        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bis = new BufferedInputStream(fis)) { // 使用 try-with-resources 语句,自动关闭流

            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = bis.read(buffer)) != -1) {
                // 处理读取到的数据
                String data = new String(buffer, 0, bytesRead);
                System.out.print(data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二、 Java NIO (Non-blocking IO)

基本概念

  • Java NIO 是 Java 1.4 引入的一组新的 I/O API,旨在提供高性能、非阻塞的 I/O 操作。
  • NIO 使用 通道 (Channel)缓冲区 (Buffer) 的模型,而不是流。
  • NIO 主要是 非阻塞式 I/O (Non-blocking I/O),即线程在执行 I/O 操作时不会被阻塞,而是可以执行其他任务。
  • NIO 使用 选择器 (Selector) 来监听多个通道的事件,实现单线程管理多个连接。

核心组件

通道 (Channel):

  • 通道类似于流,但可以进行双向数据传输(既可以读取数据,也可以写入数据)。
  • 常见的通道:
    • FileChannel: 用于文件 I/O。
    • SocketChannel: 用于 TCP 网络 I/O (客户端)。
    • ServerSocketChannel: 用于 TCP 网络 I/O (服务器端)。
    • DatagramChannel: 用于 UDP 网络 I/O。

缓冲区 (Buffer):

  • 缓冲区是用于存储数据的容器,本质上是一个字节数组 (ByteBuffer) 或字符数组 (CharBuffer)。
  • NIO 使用缓冲区进行数据传输,而不是直接从通道读取数据或向通道写入数据。
  • 常见的缓冲区:
    • ByteBuffer: 字节缓冲区。
    • CharBuffer: 字符缓冲区。
    • ShortBuffer: 短整型缓冲区。
    • IntBuffer: 整型缓冲区。
    • LongBuffer: 长整型缓冲区。
    • FloatBuffer: 浮点型缓冲区。
    • DoubleBuffer: 双精度浮点型缓冲区。

选择器 (Selector):

  • 选择器允许单个线程监听多个通道的事件(例如连接建立、数据可读、数据可写等)。
  • 使用选择器可以避免为每个连接创建一个线程,从而提高并发性能。

NIO 操作流程 (以读取 SocketChannel 数据为例)

  1. 创建 ServerSocketChannel 监听客户端连接。
  2. 创建 SocketChannel 接受客户端连接。
  3. SocketChannel 注册到 Selector 指定要监听的事件(例如 OP_READ, OP_WRITE, OP_CONNECT, OP_ACCEPT)。
  4. 创建 ByteBuffer 用于存储读取到的数据。
  5. 调用 selector.select() 方法: 阻塞等待有事件发生的通道。
  6. 获取就绪的通道: selector.selectedKeys() 返回所有就绪通道的集合。
  7. 处理事件: 遍历就绪通道的集合,根据不同的事件类型执行相应的操作(例如读取数据、写入数据)。
  8. 读取数据: 调用 channel.read(buffer) 从通道读取数据到缓冲区。
  9. 处理缓冲区数据: 从缓冲区读取数据并进行处理。
  10. 关闭通道和选择器: 在完成操作后,务必关闭通道和选择器,释放资源。

代码示例 (使用 SocketChannel 读取数据):

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NIOExample {
    public static void main(String[] args) throws IOException {
        // 1. 创建 SocketChannel
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("www.example.com", 80));
        socketChannel.configureBlocking(false); // 设置为非阻塞模式

        // 2. 创建 ByteBuffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        // 3. 从 Channel 读取数据到 Buffer
        int bytesRead = socketChannel.read(buffer);

        while (bytesRead > 0) {
            // 切换到读模式
            buffer.flip();

            // 4. 从 Buffer 读取数据
            while (buffer.hasRemaining()) {
                System.out.print((char) buffer.get());
            }

            // 清空 Buffer,准备下一次读取
            buffer.clear();
            bytesRead = socketChannel.read(buffer);
        }

        socketChannel.close();
    }
}

三、 Java IO 与 NIO 的区别

特性Java IO (Blocking IO)Java NIO (Non-blocking IO)
数据传输方式基于流 (Stream)基于通道 (Channel) 和缓冲区 (Buffer)
I/O 模型阻塞式 I/O (Blocking I/O)非阻塞式 I/O (Non-blocking I/O)
选择器没有有 (Selector)
API简单易用相对复杂,需要理解通道、缓冲区、选择器等概念
性能性能较低 (高并发下)性能较高 (高并发下)
线程模型通常使用多线程模型 (每个连接一个线程)通常使用单线程多路复用模型 (一个线程管理多个连接)
适用场景低并发、连接数较少的应用,或者可以接受阻塞的场景高并发、连接数较多的应用,需要高性能和非阻塞的场景,例如网络服务器、聊天服务器等

四、 选择哪种 I/O 模式?

  • 如果你的应用是低并发、连接数较少,并且可以接受阻塞,那么 Java IO 仍然是一个不错的选择,因为它简单易用。
  • 如果你的应用是高并发、连接数较多,并且对性能要求很高,那么应该使用 Java NIO。
  • 一般情况建议直接使用NIO模型,性能更好。

总结

Java IO 和 NIO 都是 Java 平台提供的用于进行输入和输出操作的 API。

Java IO 基于流的模型,使用简单但性能较低; Java NIO 基于通道和缓冲区的模型,提供高性能、非阻塞的 I/O 操作。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java使用Jsoup组件生成word文档

    java使用Jsoup组件生成word文档

    java使用Jsoup组件生成word文档的方法
    2013-11-11
  • 读取Java文件到byte数组的三种方法(总结)

    读取Java文件到byte数组的三种方法(总结)

    下面小编就为大家带来一篇读取Java文件到byte数组的三种方法(总结)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • Springboot热部署实现原理及实例详解

    Springboot热部署实现原理及实例详解

    这篇文章主要介绍了Springboot热部署实现原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • Java中的信息摘要算法MessageDigest类用法详解

    Java中的信息摘要算法MessageDigest类用法详解

    这篇文章主要介绍了Java中的信息摘要算法MessageDigest类用法详解,java.security.MessageDigest类为应用程序提供信息摘要算法的功能,如MD5或SHA-1或SHA-256算法,信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值,需要的朋友可以参考下
    2024-01-01
  • Spring-data-redis操作redis知识总结

    Spring-data-redis操作redis知识总结

    这篇文章主要介绍了Spring-data-redis操作redis知识总结,spring-data-redis是spring-data模块的一部分,专门用来支持在spring管理项目对redis的操作。
    2017-04-04
  • IDEA中设置背景颜色的步骤

    IDEA中设置背景颜色的步骤

    在IntelliJ IDEA中,用户可以通过访问【Settings】或【Preferences】菜单,进入【Editor】>【ColorScheme】选项来选择和调整编辑区域的颜色方案,此外,通过【Appearance & Behavior】>【Appearance】选项
    2024-09-09
  • Java MultipartFile实现上传文件/上传图片

    Java MultipartFile实现上传文件/上传图片

    这篇文章主要介绍了Java MultipartFile实现上传文件/上传图片,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-12-12
  • springboot整合shiro与自定义过滤器的全过程

    springboot整合shiro与自定义过滤器的全过程

    这篇文章主要给大家介绍了关于springboot整合shiro与自定义过滤器以及Shiro中权限控制的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-01-01
  • IDEA 搭建maven 安装、下载、配置的图文教程详解

    IDEA 搭建maven 安装、下载、配置的图文教程详解

    这篇文章主要介绍了IDEA 搭建maven 安装、下载、配置,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • 手把手教你用Java给暗恋对象发送一份表白邮件

    手把手教你用Java给暗恋对象发送一份表白邮件

    随着我们学习java的深入,也渐渐发现了它的一些乐趣,比如发送邮件,下面这篇文章主要给大家介绍了关于如何利用Java给暗恋对象发送一份表白邮件的相关资料,需要的朋友可以参考下
    2021-11-11

最新评论