前言
我们在学习C/C++的时候都学习过文件操作
C:fopen,fclose,fgets等等
C++:ofstream,ifstream,fstream
当然,其他语言也有相应的对文件的操作
这些都是站在语言的层面,而本篇博客,我们要从操作系统的角度去看待文件
那么话不多说,我们立刻进入今天的学习
一. 系统角度的文件操作
首先,我们需要理解,什么是文件
文件 = 内容 + 属性
文件操作 = 对内容的操作 || 对属性的操作
紧接着,回想一下,我们在语言层面的文件操作是不是都需要先打开文件
那么,文件最开始存储在哪呢?
文件一般存放在磁盘
打开文件 = 将文件加载到内存
文件的加载 = 属性的加载 +(内容的加载)
因为冯诺依曼体系结构,CPU只和内存做交互,所以要对文件做修改就需要加载到内存
其次,我们会同时打开多个文件,也会有别人同时打开文件
所以,操作系统需要管理这些打开的文件
如何管理?
管理 = 先描述,再组织
操作系统同样会像管理进程那样,也给文件创建对应的结构体,然后文件之间会有一些连接关系
这样,对文件的管理就变成对某种数据结构的管理
操作系统给文件创建的结构体时struct file
文件操作是谁进行的呢?
是用户让操作系统进行的
操作系统会为之创建进程
所以文件操作实质是进程和被打开文件的关系
二. 文件操作函数接口
在学习C语言时,我们见到的函数有很多种:我们自己写的函数,C语言库函数,还有sleep这样的系统函数。
如我们第一部分所说,不同语言都有文件操作的函数,但他们的本质其实还是调用系统函数
接下来,我们就来学习系统的文件操作函数 -- open&close
在学习这个函数时,我们首先要了解这个函数的参数和返回值
参数名称 | 参数说明 |
---|---|
const char *pathname | 文件路径+名称 |
int flags | 选项 – 标志位(位图) |
mode_t mode | 文件权限(八进制) |
返回值:int | 文件描述符 |
第一个参数就是要创建/打开的文件的名称
但二个参数flags不是单纯的一个整型数字
。接下来我们重点学习一下
1. 标志位 – 位图
说到标志位,我们可能很懵逼。但是说到位图,我们就有所耳闻了。
在进程等待 – waitpid函数中
这个status所接受的整数,就会被拿来当作位图使用。
这个int的32位数字的后16位不进行操作,0—7位代表终止信号,8—15位代表退出码
而open的这个flags也是相同的道理,只不过flag是每一位都有特殊的意义
我们再用一个小代码解释位图的使用
我们定义多个宏,每个宏对应二进制的前5位。通过Print中对每一位的提取,我们进行不同的操作
这就是标志位 – 位图的作用
那么对于flags,操作系统也定义了很多对应不同操作的宏
还有很多很多,我们接下来先学习最常用的几个
2. 常用打开方式
首先,我们要对文件进行操作,第一步就是打开文件/创建文件
,与之对应的宏是 O_CREAT
写文件
对应的宏是O_WRONLY
我们先试着创建一个文件
文件是成功创建了,但是对应的权限确实乱码。因为我们并没有设置他的权限
设置权限就是第三个参数mode
这样我们就按照自己的预期成功创建了一个文件
(1). 写文件
写文件的函数是 – write
接下来我们尝试写文件
如果我们写入\0,也就是
那么文件内部会变成这样
所以文件的写入,我们最好不要将\0写入文件。然后在将文件内容读出时,我们需要自己手动添加\0
当我们改变写入的内容并且就写入1次
我们会发现,原先的一部分内容被覆盖了。
O_WRONLY只是单纯的写入,不会进行内容清理,也不会追加,而是直接覆盖
而O_TRUNC代表打开时清理之前写入内容
接下来,我们介绍追加
O_APPEND
(2). 读文件
读文件的宏是O_RDONLY
读文件的函数是 – read
返回值是读取的字符个数
3.返回值
我们编写一段代码展示
此时我们没有创建log.txt文件
所以打开文件失败/未创建文件,返回-1,并修改errno
当我们有log.txt这个文件后
成功调用open函数后,返回一个文件描述符
三. 文件操作实质
结合我们之前学得C/C++的文件操作的函数接口,还有我们今天学习的操作系统的系统调用接口。这二者的关系是什么呢?
我们用下图作解释
如图,其实C/C++库的文件操作的函数接口,其内部一定调用系统的函数接口
,也就是封装系统调用。
语言层面的函数调用是无法跨过操作系统直接访问硬件的
我们在语言层面使用的文件操作,其实也只是将操作交给操作系统完成
结束语
本章对文件操作的第一次学习就到这了,感谢您的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。