文件只有站在系统层面
才能彻底理解
简单回顾一下文件:
首先我们要明确一点,我们说的打开文件不是写下fopen就打开文件,而是当我们的进程运行起来,进程打开的文件。
我们在C语言一般都会使用过如下的代码进行向文件中写入
但是除了此方法我们还有重定向也可以向文件中写入。
重定向的性质
- 当没有文件时创建文件,有文件时清空文件
- 将原本向一个文件输出的数据转移到另一个文件
同样,我们也可以使用"a"
与追加重定向
进行追加
故我们由此可以得出一个结论:重定向一定是与文件操作有关的。
提炼一下对文件的理解:
我们已经说过,是进程在打开文件,那么文件没有被打开的时候,文件在哪里?
答案是在磁盘
中。
我们的一个进程可以打开多个文件,同时我们也可以同时运行多个进程。那么OS是不是要将进程进行管理呢?
答案是一定的,我们要用到先描述在组织
的思想进行管理
于是我们可以预测一波,OS内部一定有类似PCB的内核数据结构
那么此时我们有个疑问?
每种语言对文件的操作都不一样,这样我们的学习成本岂不是大大增加了吗,为什么要这样做呢?
理解文件:
a. 操作文件,本质是进程在操作文件。
b. 文件->磁盘->外设->硬件->向文件中写入,向硬件中写入->OS是硬件的管理者->我们通过OS进行文件写入->我们不能直接向操作系统写入(操作系统必须确保硬件的良好运行防止数据被污染)->操作系统提供系统调用
函数->我们使用C语言的fprintf,fread...是对系统调用的封装。
那么问题来了,我们为什么要使用系统调用呢?
怎么使用呢?(这个先不提)
使用系统调用函数:
既然是对系统调用的封装,那我们先看看系统调用的代码&&现象:
在此之前我们贴一下需要用到的系统调用函数。
打开文件:
关闭文件:
写入:
代码实践:
第二个的第一个参数为三个,先来解释一下这三个的含义,
不存在就创建,只写入,重新打开会清空。
现象:
于是现在我们有两个疑问:
0666
是什么O_CREAT
...是什么
对于1,我们在上图已经展示过open有两个形式,虽然像重载但不是重载!
第一个open一般是针对已经创建好的文件,第二个是还没有创造的文件。
0666就代表当前文件的权限。
那么我们的文件就应该是rw_rw_rw
但是却不是,这是由于我们的mask值在作祟,我们设置的权限会与mask值做一系列操作变成图示权限。
我们也可以更改mask。
对于第二个问题,这其实是OS系统调用接口的一种常见的方法,这个方法叫做位图,我们的一个int是有32的比特位的,故我们可以利用位操作来进行控制32个比特位。
具体看如下代码,宏应该用大写!!我太懒就没改了,要大写!
于是我们就大概的了解了这些函数参数的意义。
此时我们也发现一个事情:
就是我们上图的系统调用与C语言的fopen的"w"
很相似,他们有什么联系呢?
同时,我们将O_TRUNC换为O_APPEND即可得到与fopen的"a"
很相似,那么他们又有什么关系呢?
另外,我们经过程序验证,
发现没有0 1 2,这三个是什么文件呢?
答案是
这是不是也与我们C语言默认就有的三个流一样呢?
这三者到底有什么关系ne?
在这之前,我们还要有两个东西要理解:
fd
与一切皆文件
fd的理解:
fd
是每个文件都会有的唯一标识符。
我们已经说过,OS对于文件的管理一定也会有内核数据结构的存在。
图示并不完整,struct file还指向一块缓冲区
与方法表(方法表等会会提到)
那么看完上图后,fd是啥我们依旧不知道呀。
当我们向一个文件写入时,当前进程会根据你穿给write的下标找到文件描述符表对应的下标
,找到对应的struct_file对应的缓冲区
写入,没错,文件描述表的下标记就是fd
!!
一切皆文件:
我们fd的0 1 2是默认打开的,为什么可以把硬件当做文件打开呢?
一切皆文件这个概念如何理解呢?
接下来我们一起探究一下。
于是,在linux下一切接文件!!
解决上边的三个问题:
我们在访问文件时,OS只认fd,所以,FILE
内部一定有fd,一定是对系统调用的封装。
现象:
C语言中的标准输入(stdin)、标准输出(stdout)和标准错误(stderr)本质上是对进程默认打开的文件描述符
的封装。
为什么要封装呢?
为了语言的跨平台性!
linux,windows,macos等等操作系统的文件操作的系统调用的接口必然是不一样的,若我们使用系统调用,就会失去语言的跨平台性!
所以所有的语言都想有跨平台性,所以必须封装->不同语言封装的接口就会出现差别了。
欲知后事如何,请看下回分解~~