• 深入理解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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

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

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

  • 相关阅读:
    品牌线上打假,应防微杜渐
    32天高效突击:框架+性能优化+微服务+分布式,笔记面试全有
    列表类型高级用法
    HDU-3549 Flow Problem 简单最大流
    【最全】PS各个版本下载安装及小试牛刀教程(PhotoShop CS3 ~~ PhotoShop 2022)
    某工控图片上传服务 CPU 爆高分析
    有营养的算法笔记五
    NPOI导出千分位带.00格式显示
    自动还款业务事故案例,与金融场景幂等性思考
    OVS-DPDK 流表查询详解
  • 原文地址:https://blog.csdn.net/whc18858/article/details/127712384