文章目录
- 一、文件的基本了解
- 1. 文件 = 内容 + 属性
- 2. 文件被访问之前,要被打开
- 3. 谁在打开文件?
- 二、fopen()
- w 方式打开文件
- ① 基本使用:
- ② 标准重定向:
- a 方式打开文件
- ① 基本使用:
- ② 重定向:
- fopen()定位文件
- 三、默认打开的文件流
- 四、文件描述符
- 描述文件的结构体
- ① 硬件提供各自的操作方法
- ② 使用结构体描述硬件,并管理起来
- ③ VFS:虚拟文件系统
- 文件描述符的存在
一、文件的基本了解
1. 文件 = 内容 + 属性
文件由内容和属性组成。
文件的权限,创建时间,拥有者等都是文件的属性,如下:
文件中写了些什么,就属于文件的内容了。
2. 文件被访问之前,要被打开
那么为什么要将文件加载到内存中呢?—— 文件必须被加载到内存中,这样 CPU
才能通过执行代码来修改它。
所以按照文件是否被加载到内存中,可以将文件分类:内存文件(被打开的),磁盘文件(未被打开的)。
3. 谁在打开文件?
是进程在打开文件。代码中有 fopen()
等函数,该程序形成进程后,CPU
调度该进程,执行到 fopen()
后才打开文件。
那么,一个进程是可以打开多个文件的,一段时间内,系统中又会有很多进程,所以系统需要将这些进程打开的文件进行管理,方法是:先描述,后组织。
- 先描述:使用一个结构体/类来描述文件(
struct file
),里面成员是文件的各种属性等,然后就可以创建具体的类对象来代表某个文件了。 - 再组织:将所有文件的类对象使用某种数据结构链接起来。
这样,进程和文件的关系就变为了 task_struct
和 struct file
之间的关系,对文件的管理就变成对它的数据结构的增删查改了。
二、fopen()
fopen()
函数是一个用来打开文件的函数。
它的两个参数:
filename
:文件名。看你要打开哪个文件。mode
:打开方式。看你是要 “只读” 打开呢,还是 “又读又写” 打开。
mode
总计是有 6 种可选择的,如下:
下面我们从两个基本的方式 “w”
和 “r”
方式来看一下 fopen()
函数的基本使用。
w 方式打开文件
以该方式打开一个文件的情况是:(创建)+ 清空 + 写入。
如果要打开的文件存在就打开,不存在就创建一个再打开,然后将文件内容清空,再写入内容。
① 基本使用:
首先我们来看 file.txt
(这个是我们要操作的文件)里面的内容,是有内容的:
(cat + 文件名
该指令可以查看文件内容)
然后我们查看一下 test.c
文件(源文件)的内容:
然后我们将 test.c
文件编译成可执行程序 test
,并运行:
从上面我们可以看到对 file.txt
文件以 w
方式进行打开后, file.txt
文件中原本的内容 #include<stdio.h>
没有了,而是重新写入的 hello zzz
。
② 标准重定向:
标准重定向写入时,其实是以 w
方式打开的,所以标准重定向每次也会对文件进行清空。
a 方式打开文件
以该方式打开一个文件的情况是:(创建)+ 追加。
如果要打开的文件存在就打开,不存在就创建一个再打开,然后直接在文件内容基础上,写入内容。
① 基本使用:
查看 test.c
文件中的内容,是以 a
方式打开的:
然后运行程序,我们可以看到 file.txt
文件前后内容上是添加了 hello zzz
的,是直接在原本的内容基础上追加的,而不是清空后再写入的:
② 重定向:
重定向其实是以 a
方式打开的文件,进行了追加:
fopen()定位文件
- 如果
filename
参数种没有路径,只是一个文件名的话,就在【当前路径】下查找文件,没有的话就新建一个。
进程在启动时,会自动记录自己启动时所在的路径,这就是【当前路径】。 - 如果
filename
参数种带了路径,那就在【所给路径】下查找或创建文件。
所以如果不想在当前路径下创建文件的话,可以在fopen()
中写上路径。
示例:
该程序会在上级路径下创建一个 f.txt
的文件,并写入 hello zzz
,我们来看一下:
三、默认打开的文件流
系统会默认打开三个文件:stdin
(标准输入), stdout
(标准输出), stderr
(标准错误)。
四、文件描述符
描述文件的结构体
① 硬件提供各自的操作方法
不同设备的操作方法是不同的,但都会提供操作的函数:
② 使用结构体描述硬件,并管理起来
每种硬件都用统一的结构体对象描述,这样就可以统一的管理这些硬件了,将这些对象使用某种数据结构链接起来,对这些硬件的管理就可以转变为对数据结构的增删查改了。
③ VFS:虚拟文件系统
VFS
是 Linux
内核的一个软件层,提供了一个统一的文件模型,使应用程序能够访问不同的文件系统和设备。
文件描述符的存在
那么文件描述符是什么呢,在哪里存在呢,有什么作用呢?我们来看一下整体结构:
- 上文已经说过了,系统会对进程打开的文件尽心管理,所以上图的右侧就是文件管理部分,操作系统管理的文件列表,使用统一的结构体描述的不同硬件文件,在文件被加载到内存上后,就会被放到操作系统管理的文件列表中。
- 当文件被加载到内存后,我们怎么知道是哪个进程需要的这个文件呢?—— 通过文件描述符表。我们看上图的左侧,当我们某个进程打开某个文件后,该文件就被会添加到进程的文件描述符表中,通过指针指示,进程就可以找到加载后的文件了。
- 从图中我们还可以看到,文件描述符表其实是个数组,是个数组的话那就会有下标,该下标就是文件描述符。同时数组中的
0
、1
、2
位置其实分别指向的是键盘、显示器、显示器,其实是stdin
,stdout
,stderr
三个文件,也就是上面我们所提到的默认打开的三个文件流,默认打开其实就是每个进程创建时,文件描述符表的前三个位置就已经有数据了,就是那三个文件,当然这三个文件也是可以手动关闭的。
因为文件描述符(数组下标)和进程打开的文件对应,所以在上层可以使用文件描述符 fd
来代表该进程打开的文件。
本文到这里就结束了,如果对您有帮助,希望得到您的一个赞!🌷
如有错漏,欢迎指正!😄