文件fd
a.操作文件的本质 , 比如打开文件 , 关闭文件 , 并不是代码在打开和关闭 , 他的本质就是进程对文件的操作
b.总的来说 , 用户是没有权力直接向文件中写入数据的 , 因为OS并不相信任何人 , 他会给用户提供一套系统调用的方法来进行使用 , 达到简介写入文件的操作需求
1.系统调用的文件操作
首先我们来看第一个系统调用函数open
可以看到 , 这个open函数的返回值是int类型 , 然后后面还跟着一个int flags 标记位 , ok , 直接进入使用
接下来是结果
可以看到生成了一个log.txt文件 , 但是我们发现一个很奇怪的事情 , 前面的权限是一个非常奇怪的乱码
在Linux里面 , 当你想创建一个文件的时候 , 是必须要给他一个起始权限的 , 而在这里的open有两个
一个是下面这种带mode的 , 另一个是上面这种不带mode的 , 这两个有什么区别呢?
第一种的open是用来操作已经存在的文件的 , 而下面这种open是用来创建文件的 , 而后面的mode则是创建的起始权限
如果想让我们创建出来的文件的权限看起来比较正常一点 , 可以在后面加上想要的权限 , 比如
运行结果
可以看到几乎是按照我们想要的权限来进行创建了, 但是这里还是有一个比较奇怪的点 , 就是我想创建的不是"666"权限吗 , 为什么到这里就变成"664"权限了?
这是因为我们OS里面有一个默认创建文件时的umask掩码
当我们输入"666"的时候 , 这个时候他就会跟系统原本的掩码发生冲突 , 就会导致最后变成"664" , 想要修改也很简单 , 只需要修改umask变成0就行了(直接在代码的第一行里面加上umask(0)即可)
那这个时候 , 既有系统默认的掩码 , 也有自己想设置的掩码 , 那么该用谁的呢?
答案是"就近原则"
a.标记位传参
我们可以看到 , open函数他后面带的一个参数是int flag , 但是我们传进去的缺是WRONLY和CREAT这些英文 , 这是为什么呢?
这就涉及到了一种传参的方式 ----->标记位传参
来看一下这段代码 , 我们就可以知道 , 所谓的标记为传参只不过是定义了一个宏定义 , 然后通过或的方式来传参 , 就可以输出我们想要的内容
b.open函数的用法
中间的参数是三个 分别是O_WRONLY | O_CREAT | O_TRUNC ,
分别的意思就是 , 只写 , 如果没有就创建 , 每打开一次文件就刷新文件的内容
而下面的write函数则是把长度为这么多的message写进fd里面 , 这个就比较好理解
2.文件描述符fd的本质是什么?
我们知道了在系统调用中fd就是一个int类型 , 那么他到底是一个什么东西呢?
我们可以通过一段代码来探讨
下面是运行结果
可以看到 , 从fd1到fd4 , 他是3-6
那为什么他不是从1-4呢?
原因很简单 , 在OS中 , 文件描述符里面,0代表的是标准输入,1代表的是标准输出,通常指的是屏幕输出,2代表的标准输出错误
知道了这些之后 , 我们再来看看fd他到底是什么东西.
在操作系统内部打开文件之后 , 就会有一个struct file 来管理这些文件 , 这些文件就用双链表来进行组织管理起来 , 这个时候OS就从对文件的管理进而转变成对双向链表的管理 , 然后他每个被打开的文件都有一个文件内核级的缓存 , 这个缓存就是OS来操作文件和磁盘之间的桥梁 , 当OS想改变文件内容的时候 , 就会通过缓存 , 然后保存到磁盘里面 ; 当想读取文件的时候 , 就会先读取磁盘 , 然后把内容映射到缓存 , 最后再输出到屏幕上面.
那我们都知道 , 一个进程可以同时管理多个文件, 对于进程来说 , 怎么分别辨认出每一个文件是哪个文件呢?
在图上面也画出来了, 在task_struct里面 , 他会有一个struct file指针数组 , 存放的是struct_file指针 , 里面的下标就是fd的值了
所以 , fd的本质就是内核的进程的文件映射关系的数组下标!!!
3.理解文件的读写操作
a.无论读写 , 都要让OS把文件内容读到相应的文件缓冲区
也就是说 , 不管如何去改 , 都要由OS从磁盘上读文件的内容放到文件缓冲区 , 然后修改 , 再刷新到磁盘上面 , 在读写操作的同时 , open正在
(1).创建file
(2).开辟文件缓冲区的空间,加载文件数据
(3).查进程的文件描述符表
(4).把file的地址填入对应的表的下标中
(5).返回下标