传统IO与NIO本质是分工协作:网络通信首选NIO(Selector多路复用),文件操作应全面采用NIO.2(Files/walkFileTree);性能差异根源于阻塞vs非阻塞、流式vs缓冲、单线程vs事件驱动模型。

Java 中传统 IO(java.io)和 NIO(java.nio 及 java.nio.file)不是简单“新旧替代”关系,而是面向不同场景的分工协作。性能差异根源不在 API 写法本身,而在底层模型——阻塞 vs 非阻塞、流式 vs 缓冲、单线程 vs 多路复用。选错模型,轻则浪费资源,重则在高并发或大文件场景下直接拖垮系统。
网络通信:NIO 是默认首选,BIO 仅限极低并发验证场景
传统 IO 每个连接绑定一个线程,1000 个客户端 = 至少 1000 个线程。线程上下文切换、栈内存开销、线程池饱和会迅速成为瓶颈。NIO 借助 Selector + Channel 实现单线程轮询成千上万连接,事件就绪才处理,CPU 利用率更平稳。
- Web 服务、IM 服务器、网关类应用必须用 NIO(或基于它的 Netty、Undertow)
- 本地调试用的简单 Socket 工具脚本,可继续用
ServerSocket+InputStream,代码短、逻辑直,没必要过度设计 - 注意:NIO 的非阻塞模式需配合事件循环,纯
FileChannel默认仍是阻塞的,要显式调用configureBlocking(false)
文件复制与读写:NIO.2 的 Files 方法已成事实标准
JDK 7 引入的 java.nio.file(即 NIO.2)不是“另一个选择”,而是对老旧 java.io.File 的全面升级。它不只快,更安全、可预测、跨平台。
-
Files.copy(source, target, REPLACE_EXISTING)底层调用操作系统原生 copy,支持原子性、符号链接保留、权限继承,比手动流复制快 2–3 倍且无 GC 压力 -
Files.walkFileTree()替代递归File.listFiles(),避免路径爆炸、空指针、权限中断等问题,适合清理临时目录、打包扫描 -
Path和Files分离设计,让路径构造(Paths.get("a/b/c"))与操作解耦,便于单元测试和 mock
小文件/高频读写:缓冲流仍有效,但别再裸用 FileInputStream
对于几十 KB 级文本配置、日志片段等,传统 IO 并非不能用,关键在于避免“裸流”:
立即学习“Java免费学习笔记(深入)”;
- 务必套一层
BufferedInputStream或BufferedReader,减少系统调用次数,性能可提升 5–10 倍 - 用 try-with-resources 自动关闭,防止句柄泄漏——这是传统 IO 最常见的线上事故源头
- NIO 的
Files.readString()/Files.write()(JDK 11+)语法更简洁,内部也做了缓冲优化,日常小文件操作推荐直接用
大文件/零拷贝场景:必须用 FileChannel.transferTo() 或 transferFrom()
当处理 GB 级视频、数据库 dump、日志归档时,传统流复制会在用户态反复搬运数据,CPU 和内存带宽成为瓶颈。NIO 提供真正的零拷贝路径:
-
sourceChannel.transferTo(position, count, targetChannel)在 Linux 上映射为sendfile(),数据全程在内核空间流转,不进 JVM 堆 - 该方法要求目标
Channel支持写入(如FileOutputStream.getChannel()),且源必须是文件通道(不能是 socket) - 若需跨文件系统复制(如 NFS → 本地磁盘),
transferTo可能退化为普通复制,此时应 fallback 到Files.copy()或分块ByteBuffer读写



















