Java IO与NIO核心深度解析(File/IO流/BIO&NIO&AIO/Buffer&Channel&Selector/Netty·高频面试真题)

Java IO 从文件读写一路延伸到高性能网络通信,BIO、NIO、AIO 和 Netty 的差异,本质上是阻塞模型和线程模型的差异。

Java IO(输入输出)是程序与磁盘、网络、外设进行数据交互的核心基础,所有文件读写、网络传输、数据持久化功能均依赖IO体系实现。Java IO历经迭代,从传统阻塞IO演进到NIO非阻塞IO、AIO异步IO,最终衍生出高性能网络框架Netty。

本文系统化覆盖六大核心模块:File文件操作、字节/字符IO流、BIO/NIO/AIO三大IO模型、NIO核心三大组件、Netty核心原理,从底层机制、语法规范、实战代码、易错坑点到大厂面试真题全覆盖,适配日常开发、笔试面试、网络编程进阶全场景。

一、File 文件操作类(磁盘文件基础)

File 类是 Java 对磁盘文件、文件夹路径的抽象封装,专门用于操作文件元数据,可实现文件创建、删除、重命名、路径判断、目录遍历等操作。注意:File 仅操作文件属性,不具备文件读写能力,文件内容读写需要依赖IO流。

1.1 File 核心构造方法

// 传入文件/目录路径
File file1 = new File("D:/test.txt");
// 父路径+子文件名
File file2 = new File("D:/file", "test.txt");

1.2 核心常用方法

判断类方法

exists():判断文件/目录是否存在;isFile():判断是否为文件;isDirectory():判断是否为文件夹;canRead()/canWrite():判断读写权限

创建删除方法

createNewFile():创建空文件;mkdir():创建单层目录;mkdirs():创建多层目录;delete():删除文件/空文件夹

获取信息方法

getName():获取文件名;getPath():获取相对路径;getAbsolutePath():获取绝对路径;length():获取文件字节大小

1.3 核心易错点

1、mkdir() 仅能创建单层目录,多级目录创建失败,mkdirs() 可创建多级目录,开发优先使用;

2、delete() 删除文件夹时,仅能删除空文件夹,非空文件夹无法直接删除;

3、File 对象创建成功,不代表磁盘文件一定存在,必须通过 exists() 判断。

本节面试真题

题目:File类能不能读写文件内容?mkdir和mkdirs的区别?

答案:File类仅操作文件元数据,无法读写文件内容;mkdir只能创建单层目录,多级目录创建失败;mkdirs可创建任意层级的多级目录,日常开发优先使用。

二、传统IO流体系(BIO核心)

IO 流是 Java 数据传输的核心载体,用于实现文件、网络的数据读写。传统 IO 按照数据类型分为字节流、字符流,按照传输方向分为输入流、输出流,是 BIO 阻塞编程的核心基础。

2.1 字节流(InputStream / OutputStream)

字节流是 IO 底层通用流,以 字节(byte) 为单位传输数据,可处理所有类型文件(文本、图片、视频、音频、压缩包),适配所有二进制数据传输场景。

核心子类:FileInputStream、FileOutputStream(文件字节流,最常用)

// 字节流文件拷贝(通用所有文件)
public class IOUtil {
    public static void copyFile(String src, String dest) throws IOException {
        try (InputStream in = new FileInputStream(src);
             OutputStream out = new FileOutputStream(dest)){
            byte[] buffer = new byte[1024];
            int len;
            // 循环读取字节数据
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
        }
    }
}

2.2 字符流(Reader / Writer)

字符流以 字符(char) 为单位传输数据,专门用于处理纯文本文件(txt、java、md、yml),底层基于字节流+编码解析,自动适配字符编码,避免中文乱码。

核心子类:FileReader、FileWriter、BufferedReader、BufferedWriter

// 字符流读取文本文件
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))){
    String line;
    // 按行读取,效率更高
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

2.3 字节流与字符流核心区别(面试必考)

1、传输单位:字节流以byte为单位,字符流以char为单位;

2、适用场景:字节流处理所有二进制文件,字符流仅处理纯文本文件;

3、编码处理:字节流不处理编码,易乱码;字符流自带编码解析,适配中文;

4、缓冲区:字符流默认带缓冲区,需手动flush刷新;字节流无默认缓冲区。

2.4 IO流核心规范

1、IO 资源属于系统资源,必须手动关闭,JVM 无法自动回收;

2、JDK7+ 推荐 try-with-resources 语法,自动关闭流,规避资源泄漏;

3、读写完成后必须刷新缓冲区,避免数据残留丢失。

三、三大IO模型:BIO / NIO / AIO

Java 共计三种IO编程模型,核心差异在于阻塞方式、线程模型、并发能力、适用场景,是网络编程、中间件、Netty面试的核心重难点。

3.1 BIO(同步阻塞IO)

核心特性:同步、阻塞、一连接一线程

客户端发起连接后,服务端单独开启一个线程处理,线程在等待连接、读取数据、写入数据全程阻塞,无数据时线程一直等待。

优点:代码简单、通俗易懂、适合小型程序;

致命缺点:并发能力极差,海量连接下线程暴涨,CPU上下文切换频繁,服务宕机;

适用场景:连接数少、短连接、低并发业务。

3.2 NIO(同步非阻塞IO,JDK1.4+)

核心特性:同步、非阻塞、单线程多路复用

NIO 彻底重构IO体系,摒弃一连接一线程模型,通过选择器复用单线程管理海量连接,线程不会阻塞等待数据,无数据时线程可处理其他任务。

优点:并发能力极强、线程资源极少、适配高并发场景;

缺点:原生NIO代码极其繁琐、BUG多(空轮询BUG)、开发成本高;

适用场景:高并发、长连接、海量连接的网络编程场景。

3.3 AIO(异步非阻塞IO,JDK1.7+)

核心特性:异步、非阻塞、操作系统回调通知

全程无需线程等待数据,由操作系统完成数据读取、写入后,主动回调程序方法处理业务,是最理想的IO模型。

优点:性能最高、无需线程轮询、资源利用率极致;

缺点:Windows支持完善,Linux支持极差,生产几乎不用;

现状:Java AIO 基本废弃,主流高并发框架均基于NIO实现。

本节面试真题

题目:BIO、NIO、AIO的核心区别?为什么生产不用AIO?

答案:BIO同步阻塞、一连接一线程、低并发;NIO同步非阻塞、多路复用、高并发;AIO异步非阻塞、系统回调、性能最优。AIO在Linux系统支持不完善,兼容性差,生产环境无落地场景,因此主流技术栈均基于NIO。

四、NIO 三大核心组件(Buffer/Channel/Selector)

NIO 整体架构由三大核心组件构成:Buffer(缓冲区)、Channel(通道)、Selector(选择器),三者配合实现多路复用非阻塞IO,是Netty框架的底层基石。

4.1 Buffer 缓冲区(数据容器)

Buffer 是 NIO 的数据存储载体,所有读写数据必须先存入缓冲区,本质是封装后的数组,支持双向读写,区别于BIO单向流。

核心子类:ByteBuffer(最常用)、CharBuffer、IntBuffer、FloatBuffer

四大核心属性

position:当前读写位置;limit:读写边界;capacity:缓冲区最大容量;mark:标记回溯位置

核心方法:flip()(切换读模式)、clear()(清空缓冲区)、rewind()(重读数据)

4.2 Channel 通道(数据传输通道)

Channel 是 NIO 数据传输的通道,对接文件、网络端口,负责连接数据源与缓冲区,双向可读可写、非阻塞、可复用。

核心子类:FileChannel(文件通道)、SocketChannel(客户端网络通道)、ServerSocketChannel(服务端网络通道)

核心特性:BIO流单向传输,Channel双向传输;支持异步读写;可配合缓冲区实现零拷贝。

4.3 Selector 选择器(多路复用核心)

Selector 是 NIO 多路复用的核心,单线程管理多个Channel,轮询监听所有通道的事件(连接、读、写),仅处理就绪的通道,彻底解决BIO线程资源浪费问题。

核心监听事件

OP_ACCEPT:客户端连接事件;OP_READ:数据可读事件;OP_WRITE:数据可写事件

工作流程:Channel注册到Selector -> Selector轮询就绪事件 -> 单线程处理所有就绪通道

4.4 NIO 原生痛点(Netty诞生原因)

1、原生NIO存在空轮询BUG,导致CPU 100%占用;

2、API繁琐、底层复杂、手动维护缓冲区、读写逻辑冗余;

3、无断线重连、心跳检测、粘包拆包机制,生产无法直接使用。

五、Netty 高性能网络框架(NIO实战落地)

Netty 是基于 Java NIO 封装的高性能、高可靠、事件驱动的网络编程框架,彻底解决原生NIO的BUG与开发痛点,是目前 Java 网络编程、RPC框架、中间件(Redis、Dubbo、RocketMQ)的底层核心依赖。

5.1 Netty 核心优势

1、修复原生NIO空轮询BUG,杜绝CPU飙高问题;

2、封装极简API,屏蔽底层NIO复杂逻辑,开发效率大幅提升;

3、内置粘包拆包、心跳检测、断线重连、流量控制机制;

4、基于主从多线程模型,并发性能极致优化;

5、支持零拷贝、内存池、对象池,资源利用率极高。

5.2 Netty 核心组件

1、Bootstrap/ServerBootstrap:客户端/服务端启动引导器,封装启动配置、绑定端口、注册处理器;

2、EventLoopGroup:事件循环组,核心线程池,负责轮询IO事件、执行任务;

3、ChannelPipeline:责任链管道,管理处理器执行顺序,实现编解码、业务处理;

4、ChannelHandler:业务处理器,处理读写、异常、连接事件;

5、ByteBuf:Netty自定义缓冲区,替代原生ByteBuffer,性能更强、操作更便捷。

5.3 Netty 主从线程模型(核心面试点)

BossGroup(主线程组):负责监听端口、接收客户端连接,不处理业务;

WorkerGroup(从线程组):负责处理已建立连接的读写事件、执行业务逻辑;

优势:连接接收与业务处理线程隔离,分工明确,高并发、高吞吐、低延迟。

5.4 粘包与拆包问题(生产高频)

问题成因:TCP是流式协议,无数据边界,多条数据会粘连、单条数据会拆分;

Netty解决方案:固定长度解码器、行解码器、自定义分隔符、长度域解码器(生产主流)。

本节面试真题

题目:Netty为什么比原生NIO性能好?

答案:Netty修复NIO空轮询BUG;优化线程模型实现高并发;内置内存池、零拷贝提升IO效率;封装完善的故障处理、粘包拆包机制;API简洁、稳定性强,适配生产高并发场景。

六、全文终极背诵总结(面试必背)

1、File类:仅操作文件元数据,不负责读写,mkdirs支持多级目录创建,是文件操作基础;

2、IO流:字节流通吃所有文件,字符流专属文本文件,BIO为同步阻塞单向流,必须手动关闭资源;

3、IO模型:BIO一连接一线程低并发,NIO多路复用高并发,AIO异步高效但Linux不兼容、生产废弃;

4、NIO核心:Buffer存数据、Channel传数据、Selector多路监听,单线程管理海量连接,是高并发IO核心;

5、Netty框架:基于NIO优化,修复原生BUG,主从线程模型,内置粘包拆包、心跳检测,是主流网络编程框架。

后浪云移动端信息流广告 后浪云主机服务 适合长期部署、独立站和海外机房需求。