计算机操作系统学习笔记(10)——文件IO

简介: 计算机操作系统学习笔记(10)——文件IO

⽂件的读写⽅式各有千秋,对于⽂件的 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

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 是分为两个过程的:


1.数据准备的过程

2.数据从内核空间拷⻉到⽤户进程缓冲区的过程

阻塞IO

阻塞 I/O,当⽤户程序执⾏ read ,线程会被阻塞,⼀直等到内核数据准备好,并把数据从内核缓冲区拷⻉到应⽤程序的缓冲区中,当拷⻉过程完成, read 才会返回。

da402bbccc06439d8d54c7cb328b27fe.png

注意,阻塞等待的是「内核数据准备好」和「数据从内核态拷⻉到⽤户态」这两个过程。


⾮阻塞 I/O

⾮阻塞 I/O,⾮阻塞的 read 请求在数据未准备好的情况下⽴即返回,可以继续往下执⾏,此时应⽤程序不断轮询内核,直到数据准备好,但是获取数据的过程,是⼀个同步的过程,仍然需要等待的过程

293596abb04345c49d2a68adb5489416.png


IO多路复用

⾮阻塞 I/O中应⽤程序每次轮询内核的 I/O 是否准备好,感觉有点傻乎乎,因为轮询的过程中,应⽤程序啥也做不了,只是在循环。

为了解决这种傻乎乎轮询⽅式,于是 I/O 多路复⽤技术就出来了,如 select、poll,它是通过I/O 事件分发,当内核数据准备好时,再以事件通知应⽤程序进⾏操作。

487dfcb53e054341bfb7aaac44bb42b4.png

实际上,⽆论是阻塞 I/O、⾮阻塞 I/O,还是基于⾮阻塞 I/O 的多路复⽤都是同步调⽤。因为它们在 read 调⽤时,内核将数据从内核空间拷⻉到应⽤程序空间,过程都是需要等待的。

说白了就是他们第二步都是需要等待的


异步 I/O

⽽真正的异步 I/O 是「内核数据准备好」和「数据从内核态拷⻉到⽤户态」这两个过程都不⽤等待。

当我们发起 aio_read 之后,就⽴即返回,内核⾃动将数据从内核空间拷⻉到应⽤程序空间,这个拷⻉过程同样是异步的,内核⾃动完成的,和前⾯的同步操作不⼀样,应⽤程序并不需要主动发起拷⻉动作。


479bb76cd0804ce292be180c5ead12dc.png

总结

06f2c708045441dbbf8d8673159bc9cb.png


举个你去饭堂吃饭的例⼦,你好⽐⽤户程序,饭堂好⽐操作系统。

阻塞 I/O 好⽐,你去饭堂吃饭,但是饭堂的菜还没做好,然后你就⼀直在那⾥等啊等,等了

好⻓⼀段时间终于等到饭堂阿姨把菜端了出来(数据准备的过程),但是你还得继续等阿姨

把菜(内核空间)打到你的饭盒⾥(⽤户空间),经历完这两个过程,你才可以离开。


⾮阻塞 I/O 好⽐,你去了饭堂,问阿姨菜做好了没有,阿姨告诉你没,你就离开了,过⼏⼗

分钟,你⼜来饭堂问阿姨,阿姨说做好了,于是阿姨帮你把菜打到你的饭盒⾥,这个过程你

是得等待的。


基于⾮阻塞的 I/O 多路复⽤好⽐,你去饭堂吃饭,发现有⼀排窗⼝,饭堂阿姨告诉你这些窗

⼝都还没做好菜,等做好了再通知你,于是等啊等( select 调⽤中),过了⼀会阿姨通知

你菜做好了,但是不知道哪个窗⼝的菜做好了,你⾃⼰看吧。于是你只能⼀个⼀个窗⼝去确

认,后⾯发现 5 号窗⼝菜做好了,于是你让 5 号窗⼝的阿姨帮你打菜到饭盒⾥,这个打菜的

过程你是要等待的,虽然时间不⻓。打完菜后,你⾃然就可以离开了。


异步 I/O 好⽐,你让饭堂阿姨将菜做好并把菜打到饭盒⾥后,把饭盒送到你⾯前,整个过程

你都不需要任何等待。

目录
相关文章
|
3月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
210 1
|
7月前
|
XML JSON Go
Go语言中的文件与IO:JSON、CSV、XML处理
本文介绍了 Go 语言中对 JSON、CSV 和 XML 三种常见数据格式的处理方法。通过标准库 `encoding/json`、`encoding/csv` 和 `encoding/xml`,可以实现结构体与数据格式之间的序列化与反序列化。JSON 适合 Web API 和前后端通信,因其清晰易读;CSV 适用于表格数据和轻量级交换;XML 则支持复杂嵌套结构,常用于配置文件和 SOAP 协议。文中提供代码示例,涵盖基本使用、嵌套结构处理及实战建议,帮助开发者高效操作这些格式。
|
7月前
|
Unix Go
Go语言中的文件与IO:文件读写
本文介绍了 Go 语言中文件操作的基础方法,涵盖打开与关闭文件、读取和写入文件内容、追加写入以及复制文件等功能。通过 `os`、`bufio` 和 `io` 等标准库包,提供了高效且灵活的实现方式,如使用 `os.ReadFile` 读取整个文件、`bufio.Scanner` 逐行读取、`os.Create` 创建文件以及 `io.Copy` 复制文件内容。同时强调了错误处理的重要性,例如使用 `defer` 确保文件关闭,并推荐注意文件权限设置(如 UNIX 系统中的 `0644`)。最后以表格形式总结了常用操作及其推荐方法,便于快速查阅和应用。
|
7月前
|
Go 数据处理
Go语言中的文件与IO:bufio 和 scanner
Go 标准库中的 `bufio` 包高效读写功能,适用于文件和数据处理。`bufio.Reader` 支持按行或分隔符读取,`bufio.Writer` 提供高性能写入并需调用 `Flush()` 确保数据写入。`bufio.Scanner` 是处理文本文件(如日志、配置)的利器,可按行、单词等分割内容。本文详解其用法,并给出实践建议,如统计字符数、模拟 `tail -f` 和词频分析等。
|
11月前
|
存储 网络协议 Linux
【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件
本文详细介绍了Linux中的进程IO与系统调用,包括 `open`、`write`、`read`和 `close`函数及其用法,解释了文件描述符(fd)的概念,并深入探讨了Linux中的“一切皆文件”思想。这种设计极大地简化了系统编程,使得处理不同类型的IO设备变得更加一致和简单。通过本文的学习,您应该能够更好地理解和应用Linux中的进程IO操作,提高系统编程的效率和能力。
489 34
|
Python
文件元数据获取方法对比:`os.path` 与 `os.stat`
本文对比了Python中两种获取文件元数据的方法:`os.path`和`os.stat`。通过示例代码展示了如何获取文件大小和修改时间,并从性能、功能性和代码可读性三方面进行了详细对比。最终给出了根据具体需求选择合适方法的最佳实践建议。
254 2
|
Java 测试技术 Maven
Maven clean 提示文件 java.io.IOException
在使用Maven进行项目打包时,遇到了`Failed to delete`错误,尝试手动删除目标文件也失败,提示`java.io.IOException`。经过分析,发现问题是由于`sys-info.log`文件被其他进程占用。解决方法是关闭IDEA和相关Java进程,清理隐藏的Java进程后重新尝试Maven clean操作。最终问题得以解决。总结:遇到此类问题时,可以通过任务管理器清理相关进程或重启电脑来解决。
|
存储 Java API
【JavaEE】——文件IO(万字长文)
文件路径,文本文件,二进制文件,File类,文件流,字节流(InputStream,OutputStream)字符流(Reader,Writer)
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用

推荐镜像

更多