目录
Linux的 > 和 >>
文件的本质 :
操作系统的系统调用函数
open:
close:关闭文件
write:
open的返回值:
操作系统视角中的“文件与进程之间的关系”:
从上图可以得知以下论点:
什么是一切皆文件?
文件和进程关系图:
C语言的FIlE * 与 fd 的关系:
文件 = 属性 + 内容
Linux的 > 和 >>
文件的本质 :
操作文件的本质是进程在操作文件,打开文件的本质实际上是进程在打开文件
访问文件可以使用系统调用来进行文件的访问 的 原因:
- a.文件是存储在磁盘上的,而磁盘是外部设备,所以向文件中写入数据,实际上是向磁盘中写入数据,但是用户并没有直接向磁盘输入数据的权限,而是需要通过操作系统的调用,才能够在磁盘中写入数据。
- b.因此,为了支持用户在磁盘中写入数据,操作系统会给用户提供相对应的系统调用。
- c.所以像C语言中的打开文件的函数 fopen 或者写入文件的函数,都其实是操作系统调用的一种封装
操作系统的系统调用函数
open:
open是打开文件的函数,open的第一个参数是需要打开的文件,注意如果需要打开的文件不在当前的路劲下,则要写全文件的路劲
open的第二个参数是文件的标识位,表示以某种方式打开文件,功能和C语言中的 "W"、"a"等等类似
如图所示,虽然使用open创建了一个文件,但是该文件的读写权限有一些问题,其实这和open的第三个参数有关系,open的第三个参数是对open创建的文件的权限进行动态调整
close:关闭文件
write:
虽然结果正确无误,但是终究还是会出现一些问题,这其实和open的标识符有关系,当使用O_WRONLY时,假设文件的内部已经具有了内容,随后我们用该标识符打开文件,并且使用了write进行数据的输入,那么我们输入的数据则会从头开始覆盖文件内部已有的数据
比如:我们在上面的已经具有文件内容的情况下,继续输入数据aaaaa则会得到以下的结果
若想要文件内容中只存在aaaa那么需要加上另一个标记位 O_TRUNC
该函数的功能和上文讲诉的 "W"和>一样,将文件的内容清空。
而诺不想要将文件的内容清空,而是想要在文件的内容之后继续添加数据则需要使用另一个标记位:O_APPEND
可以看出O_APPEND的功能和上文中的"a" 和>>一样!
open的返回值:
open的返回值其实一种文件描述符,且一般使用open打开文件,得到的文件描述符是一个从3开始的整数
为什么是从3开始的呢?因为0、1、2其实是系统调用的标准输入、标准输出、标准错误
操作系统视角中的“文件与进程之间的关系”:
从上图可以得知以下论点:
1.文件是在磁盘内部的,所以想要调用磁盘就必须通过操作系统,进行调用磁盘内部的文件,同时操作系统会对磁盘内部的文件进行管理
2.因为磁盘的内部可能会拥有成千上万个文件,这些文件有的会打开、有的会在读取,因此为了方便管理这些文件,操作系统会创建一共名为 struct file 的数据结构
3.关于struct file 这个数据结构,会分为两个部分,一个是文件内核级的缓存区域,一个是它的属性,因为文件 = 属性+内容,所以当文件打开后,会将自身的属性交给这个数据结构,而把内容交给缓存区域
4.每次打开一个文件,都会在操作系统内部创建一个struct file 结构体,当打开多个文件时,这些结构体就会相互双向链接,形成一个链表,而操作系统管理这个链表就相当于管理文件
5.因为进程需要对文件进行管理,同时在操作系统中也会存在多个进程,所以为了方便知道那些文件是那些进程打开的,操作系统在这里创建了一个指针数组 struct files_struct
6.指针数组 struct files_struct 的内部存储着各个文件的地址,同时用数组内部的下标来进行标记,且该数组被进程内部的一个指针struct files_struct *files指针,这样就可以表明这个数组内部的所有文件都是该进程打开的。
7.指针数组的下标,在进程打开,后会被操作系统拿取,变成一个返回值,而这个返回值就是文件描述符,也就是系统调用函数中最重要的一个参数 fd 也是系统调用函数 open的返回值,因此struct files_struct 这个指针数组的下标 其实就是文件描述符!
8.对于文件的读,其实本质上就是一种拷贝,让操作系统在合适的调用了磁盘中的文件内容,将内容调用到了文件内核级的缓存区中,再由用户使用函数进行拷贝读取,而对于文件的写,就是在文件内核级的缓存区中更新内容随后在将新的内容冲刷回磁盘中
9.对于open函数,它的作用本质上是 :a.在进行struct file的创建、b.进行文件内核级缓冲区的开辟、c.调查进程的文件描述符,以此来进行文件的查找,d.将文件的地址填入struct files_struct中 e.返回struct files_struct的下标
什么是一切皆文件?
1.对于每一种外部设备,它们都具有读写方法,而在之前的学习中我们知道,操作系统是需要通过驱动来对底层的硬件进行管理的,所以每一种外部设备的读写方法都即存在它们相对应的驱动之中。
2.同时,每一个设备都会由操作系统创建一个数据结构 strcut file ,每次打开一个设备,操作系统就会开始创建一个strcut file
3.同时这个数据结构 struct file 的内部具有 一个函数指针数,这个函数指针指向 会 对应的 设备驱动上的 读写方法,所以如果要使用操作系统对外部设备进行调用和访问,只需要调用struct file 内部的指针即可。
4.从上文可以看出 struct file 不仅仅是从磁盘中读取文件,还是可以读取设备上的数据,于是我们也可以得知在struct file的内部还有一个指向底层的指针表,里面寄存着指向外设的读写方法指针
文件和进程关系图:
C语言的FIlE * 与 fd 的关系:
在上面的叙述中,我们可以知道系统调用文件的过程中,是只认 文件描述符 也就是 只认fd的!
那么为什么C语言可以使用FILE*进行打开文件等操作呢?
答案是C语言中的FILE*内部具有fd,换言之,就是FILE*是fd的封装接口,变成封装接口的原因是在写代码的过程中会因为操作系统的不一致而导致某些系统调用的功能不同,所以一般推荐用户使用语言提供的调用语言来写更为合适。