⽂件的读写⽅式各有千秋,对于⽂件的 I/O 分类也⾮常多,常⻅的有
缓冲与⾮缓冲 I/O
直接与⾮直接 I/O
阻塞与⾮阻塞 I/O VS 同步与异步 I/O
接下来,分别对这些分类讨论讨论。
缓冲与⾮缓冲 I/O
⽂件操作的标准库是可以实现数据的缓存,那么根据「是否利⽤标准库缓冲」,可以把⽂件 I/O 分为缓冲 I/O 和⾮缓冲 I/O: 缓冲 I/O,利⽤的是标准库的缓存实现⽂件的加速访问,⽽标准库再通过系统调⽤访问⽂件。 ⾮缓冲 I/O,直接通过系统调⽤访问⽂件,不经过标准库缓存。 这⾥所说的「缓冲」特指标准库内部实现的缓冲。 ⽐⽅说,很多程序遇到换⾏时才真正输出,⽽换⾏前的内容,其实就是被标准库暂时缓存了起来,这样做 的⽬的是,减少系统调⽤的次数,毕竟系统调⽤是有 CPU 上下⽂切换的开销的。
直接与⾮直接 I/O
我们都知道磁盘 I/O 是⾮常慢的,所以 Linux 内核为了减少磁盘 I/O 次数,在系统调⽤后,会把⽤户数据 拷⻉到内核中缓存起来,这个内核缓存空间也就是「⻚缓存」,只有当缓存满⾜某些条件的时候,才发起 磁盘 I/O 的请求。 那么,根据是「否利⽤操作系统的缓存」,可以把⽂件 I/O 分为直接 I/O 与⾮直接 I/O: 直接 I/O,不会发⽣内核缓存和⽤户程序之间数据复制,⽽是直接经过⽂件系统访问磁盘。 ⾮直接 I/O,读操作时,数据从内核缓存中拷⻉给⽤户程序,写操作时,数据从⽤户程序拷⻉给内核 缓存,再由内核决定什么时候写⼊数据到磁盘。 如果你在使⽤⽂件操作类的系统调⽤函数时,指定了 O_DIRECT 标志,则表示使⽤直接 I/O。如果没有 设置过,默认使⽤的是⾮直接 I/O。
阻塞与⾮阻塞 I/O VS 同步与异步 I/O
为什么把阻塞 / ⾮阻塞与同步与异步放⼀起说的呢?因为它们确实⾮常相似,也⾮常容易混淆,不过它们 之间的关系还是有点微妙的。 先来看看阻塞 I/O,当⽤户程序执⾏ read ,线程会被阻塞,⼀直等到内核数据准备好,并把数据从内核 缓冲区拷⻉到应⽤程序的缓冲区中,当拷⻉过程完成, read 才会返回。