Linux基础IO(二):深入理解Linux文件描述符

一、前言

 在上一篇博客中,我们初步学习了Linux文件操作的系统接口,不难发现的是,这些系统函数都与文件描述符密切相关:open函数返回值是一个文件描述符,write函数、read函数、close函数都是对于 文件描述符 进行操作。
在这里插入图片描述
 这让我们不禁思考,文件描述符到底是什么东西呢? 先上结论,文件描述符本质就是数组下标。此时的你肯定会有不少困惑,且看下文我为大家细细展开。

二、Linux标准文件描述符

[问题一]:为什么为什么打开文件时,fd总是从3开始? 0,1,2分别是什么?
image-20221103143600412

直接上结论:fd = 0~2的标准文件是默认被打开的,分别表示为

  • 0:标准输入 → 键盘
  • 1:标准输出 → 显示器
  • 2:标准错误 → 显示器

口说无凭,我们用代码来验证上面的结论:

  1. 从标准输入中直接读取数据
    image-20221103145021094
  2. 向标准输入中写入数据
    image-20221103145427113

[总结一]:

  1. fd = 0~2的文件分别对应着标准输入、标准输入和标准错误
  2. 标准文件是默认被打开的,因此 fd 总是会从3开始增加(除非手动关闭标准文件)

三、文件描述符与FILE结构体的关系

FILE是C语言定义的文件结构体,里面包含了各种文件信息。可以肯定的一点是,FILE结构体内一定封装了 fd 。为什么?来看接下来的思路分析:

1.使用系统接口的必然性
 文件存储在磁盘上,属于外设。谁有权限访问外设呢?只有操作系统。因为操作系统对上要提供稳定的服务,对下要管理好各种软硬件资源
 如果文件操作能绕开操作系统,那么操作系统怎么知道某个文件到底有没有被创建,有没有被销毁呢,还怎么给你提供稳定的服务呢?基于上述简单的认识,我们不难理解,要想访问硬件资源,就必须通过操作系统
 而操作系统出于安全性和减少使用成本的角度考虑,是不相信任何人的。就像银行一样,不会将金库直接向大众开放,而是只会有几个业务窗口为大家提供服务。操作系统也是这样,操作系统提供的窗口就是系统接口。
 至此通过我们的逻辑推演,我们已经可以得出以下的结论:要想访问外设就必须使用操作系统提供的系统接口。所以C语言的各种文件操作函数本质就是对系统接口的封装

2.FILE结构体封装fd的必然性
 C语言的文件操作都是系统统接口的封装,而系统接口的使用只认fd,因此FILE结构体中必然会封装fd

​ 验证的方法也很简单直接:

image-20221103151323233

四、进程与文件的映射关系

在理解两者的关系之前,我们首先来回答几个问题,让大家有基础的认识:

[问题二]:打开的本质是什么?
 答:本质是将文件加载到内存。为什么要加载到内存?这是由冯诺依曼体系决定的

[问题三]:打开文件、访问文件、关闭文件,都是谁在操作?
 答:这些操作都是我们调用函数完成的,难道说是我们操作的吗?哈哈这样想就单纯了。当我们编译生成可执行文件的时候,有进行文件操作吗?答案显然是没有。我们的程序文件只有在运行起来的时候才会执行相应的代码,然后才会执行相应的文件操作。所以说这些操作本质都会由进程完成的。所以文件操作本质上是进程和打开的文件的联系

[问题四]:OS如何管理大量的文件呢?
 答:当文件被打开时,文件是存在于内存中的,因此内存中当然会存在大量的文件。操作系统要不要管理这些文件呢?答案是肯定的。如何管理呢?显然是是先描述后组织的设计思想:
 一个文件被打开,在内核中就要创建对应的内核数据结构struct file(先描述),然后通过链表的方式将各个文件组织起来(后组织)。伪代码形式如下:

struct file
{
     
     
   // 文件内容和属性成员变量
   struct file* next;
   struct file* prev;
}

 有了上述的基本认识之后,我们基于Linux 内核源码,再来具体谈谈进程与文件的映射关系:

进程控制块 task_struct 中有一个类型为 files_struct 的文件指针,files _struct
在这里插入图片描述
在这里插入图片描述
 在 files_struct 有一个成员类型为 file* 的指针数组,数组中的每个指针变量就对应着被该进程打开的文件。所以 fd 本质上就是 fd_array 数组的下标 file*结构体表示文件的各种基本信息。
 在用这样一张图来为大家梳理思路:
在这里插入图片描述

[问题五]:文件描述符的分配规则
 答:从头遍历fd_arr数组,找到一个最小的没有被使用的下标,分配新的文件。如果我们手动将 fd = 1 的文件关闭,那么新创建文件的 fd 就等于1。

猜你喜欢

转载自blog.csdn.net/whc18858/article/details/127712384