【杂类】I/O
一句话概括
I/O 操作就是你的程序与外部世界“打交道”的过程。
这个“外部世界”可以是:
- 硬件:硬盘上的文件、键盘、鼠标、显示器、网卡...
- 其他程序:通过网络与另一台电脑上的程序通信。
一个生动的比喻:厨房做饭
想象你是一个厨师(CPU,负责处理任务),在厨房(内存,工作间)里做饭。
从冰箱拿食材(读操作 - Input)
- 你走到冰箱(硬盘/磁盘)前,打开门,把里面的鸡肉和蔬菜(数据)拿到厨房的操作台上(内存)。
- 这个过程就是 Input(输入/读):从外部设备(冰箱)将数据(食材)读取到内存(厨房)中供程序(你)处理。
把做好的菜放进冰箱(写操作 - Output)
- 菜做好了,你把它装盘,然后打开冰箱门,把菜放进去保存。
- 这个过程就是 Output(输出/写):将内存(厨房)中处理好的数据(菜)写入到外部设备(冰箱)中保存起来。
整个“走去冰箱-打开门-拿/放东西-关上门-走回来”的过程,就是一个 I/O 操作。 关键点在于:它很慢! 它会让你(CPU)停下来等待。
为什么 I/O 操作很“昂贵”(慢)?
继续用厨房的比喻:
- 你(CPU)处理速度极快:切菜、炒菜可能只需要几秒钟。
- 但你走去冰箱(I/O)的过程极慢:可能需要几十秒甚至几分钟。
计算机也是如此:
- CPU 和内存的速度:是纳秒(十亿分之一秒)级别的。
- 硬盘、网络等 I/O 设备的速度:是毫秒(千分之一秒)级别的。
速度差距是几十万甚至上百万倍! 因此,当程序执行 I/O 操作时,它必须停下来等待数据从慢速的设备传来,这极大地拖慢了程序的整体效率。
常见的 I/O 操作有哪些?
几乎所有与“外部”打交道的事情都是 I/O 操作:
I/O 类型 | 具体例子 | 说明 |
---|---|---|
磁盘 I/O | 读写硬盘上的文件、启动一个程序 | 程序从磁盘加载数据到内存,或将内存中的数据保存到磁盘。 |
网络 I/O | 访问一个网页、发微信消息、查询数据库(数据库通常在另一台机器上) | 你的程序通过网络卡与另一台机器上的程序进行数据交换。 |
数据库 I/O | 从 MySQL 中查询用户数据 | 这本质上是网络 I/O(如果数据库在远程服务器)和磁盘 I/O(数据库最终要读写磁盘)的组合。 |
设备 I/O | 从键盘输入、在显示器上显示、用鼠标点击 | 与输入输出设备的交互。 |
一个简单的代码例子:
// 这是一个非常典型的【文件 I/O 操作】(写 - Output)
import java.io.*;public class TestIO {public static void main(String[] args) {// 程序(内存) => 文件(磁盘):Outputtry (FileWriter writer = new FileWriter("test.txt")) {writer.write("Hello, World!"); // 数据从内存写出到磁盘}// 文件(磁盘) => 程序(内存):Inputtry (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {String line = reader.readLine(); // 数据从磁盘读取到内存System.out.println(line);}}
}
如何应对 I/O 的“慢”?—— 两种重要策略
因为 I/O 是瓶颈,所以程序员想出了很多办法来优化:
缓冲(Buffering)
- 比喻:你不是做一盘菜就往冰箱跑一次,而是用一个推车(缓冲区),攒够五六盘菜再一次性推过去放好。
- 技术:
BufferedOutputStream
,BufferedReader
。将多次小的 I/O 操作合并成一次大的 I/O 操作,减少来回次数,显著提升效率。
异步 I/O(Asynchronous I/O)
- 比喻:你不是自己傻站着等冰箱门开关。你雇了一个助手(另一个线程),对他说:“去帮我把冰箱里的鸡肉拿来,拿好了叫我。” 然后你就可以继续切菜(处理其他任务),不用干等着。
- 技术:
Future
,回调函数,NIO。在等待 I/O 结果的同时,CPU 可以去执行其他任务,极大地提高了系统的整体吞吐量。
总结
- I/O:Input/Output(输入/输出),指程序与外部设备(如磁盘、网络、其他程序)的数据交换。
- 核心特点:速度极慢,是程序性能的主要瓶颈。
- 关键目标:尽量减少 I/O 次数(用缓冲)或避免在 I/O 时空等(用异步)。
理解了 I/O,你就理解了为什么数据库优化、缓存技术(Redis)、异步编程等如此重要——它们都是为了解决这个核心的“慢”问题。