文件系统之程序是怎么打开文件进行操作的

本篇文章自顶向下,从文件系统的上层出发讲到磁盘,帮助理解程序是如何打开文件并进行后序的读写操作的,读到后面,前面的一些疑惑就得到解决

介绍相关概念

注意,目录也是文件

文件描述符

每个进程都有一个指针*files,指向一张表files_struct,该表最重要的部分就是包涵一个指针数组的struct_file*fd_array 每个元素都是一个指向打开文件的指针(fd)!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。
当我们使用系统调用open来打开文件时,我们会发现打开open函数会返回一个int类型的数据,在man手册中我们可以看到,这个int类型的数据叫做文件描述符,简称 fd。那么open函数是怎么做的呢?
OS会拿到open函数传入的实参pathname,然后根据路径名在文件系统中的目录项中查找该文件,如果找到了就返回 fd,没有找到就返回-1,并设置错误码。

在这里插入图片描述
在进程PCB中,会维护一个文件描述符表,该表可以想象为1个数组,fd是索引,该表存放的就是进程所打开的文件的文件描述符 fd,文件描述符一般会由OS选择表中最小的没有被使用的描述符作为当前要打开的文件的 fd。
fd 与 文件的 iNode 相关联,通过fd 就可以找到文件的iNode。

文件表

  • 文件表处于文件系统中间的位置,属于进程,被进程单独维护。
  • 在Linux系统中,文件表通常是由一个链表来维护的,每个文件表项都有一个指向下一个文件表项的指针。
  • 其上下层关系如下:
    • 下层 - iNode :

      • inode和文件数据块
      • 每个文件在磁盘上都有一个对应的inode,存储文件元信息
      • 文件数据存储在数据块中
      • inode包含了指向数据块的指针
    • 中层 - 文件表

      • 文件表跟踪每个进程打开的文件信息
      • 每打开一个文件,在文件表创建一个文件表项
      • 文件表项包含了文件描述符、打开模式、当前偏移等信息
      • 通过文件描述符可以找到对应的inode
    • 上层 - 虚拟文件系统(VFS)

      • VFS提供统一的文件系统操作接口给上层应用,如open
      • 接收应用层的操作请求,转换为对具体文件系统的调用
      • 调用文件表接口实现对打开文件状态的跟踪

iNode(index-node)

  • iNode在linux内核中是一个结构体,每一个文件对应一个iNode号,包含文件的各种属性信息,比如文件占用的逻辑块数量,文件实际数据块的指针数组(指向了文件数据实际在磁盘中存储的位置),文件的权限,文件的修改时间,文件大小等信息。我们要通过 fd 找到 iNode,再通过iNode中设置的文件数据存储的数据块的地址来找到文件数据实际存储在磁盘的哪个扇区(物理块)。
  • 要注意的是,iNode中所指向的数据块地址的字段不一定是直接指向数据实际存储的地址,iNode中存储的可能是间接地址。
  • 具体地说,inode中存储了12个指向数据块的直接指针(如果文件大小<=12个数据块,这些指针就足够了),还包括一个一级间接块指针、一个二级间接块指针和一个三级间接块指针。这些指针分别指向一级、二级、三级块指针数组,这些数组中存储了更多的数据块地址。如果inode中的数据块数组直接索引到数据,那么数据块数组的大小开多大就是一个问题。所以通过上面存储指针的方式,文件系统可以支持非常大的文件,同时减少了inode的空间占用,解决了inode的存储空间问题。
  • 同时,指针块不需要完全填满,可以按需分配,避免过多无用空间。
  • 通过直接指针和多级间接指针的组合,iNode可以支持对大文件的数据寻址,最大可以支持GB级的数据量。

磁盘抽象之文件系统

文件系统是OS的一个子集,用于管理文件。这里介绍一下文件系统的简单布局:在这里插入图片描述

各个字段介绍

  • 磁盘被划分为一个或多个分区,每个分区中有一个独立的文件系统。磁盘的0号扇区称为主引导记录(Master Boot Record,MBR),用来引导计算机。该表给出了每个分区的起始和结束地址。表中的一个分区被标记为活动分区。在计算机被引导时,BIOS读入并执行MBR。MBR做的第一件事是确定活动分区,读入它的第一个块,称为引导块(boot lock),并执行之。引导块中的程序将装载该分区中的操作系统。为统一起见,每个分区都从一个引导块开始。
  • 说人话就是:
    • 想象一下你的电脑是一辆车,启动电脑就像启动车辆一样需要一个启动过程。
    • MBR就像车钥匙,当你转动钥匙(加电启动)时,BIOS读入并执行MBR,它(MBR)包含了启动计算机最基本的程序(引导代码)。这些基本程序知道下一步应该去运行哪些程序,比如启动Windows或Linux系统的核心程序。
    • 类似钥匙会转动点火、启动发动机,MBR中的引导代码启动了计算机,将控制权转交给操作系统,使计算机能正常工作。
    • 另外在MBR的结尾是分区表,该表给出了硬盘的每个分区的起始和结束地址。记载了硬盘里面数据都存放在哪些区域,就像车里各个存放物品的地方一样。但现在新车型(新电脑)已经用更先进的分区方式了。这里不做介绍。
  • 超级块(Superblock)
    我们可以把文件系统想象成一个图书馆。
    超级块就像图书馆的目录,它记录了这个图书馆的全局信息:
  • 图书馆有多大,可以存放多少本书(文件系统的大小)
  • 书籍资源如何组织,按哪些规则排序(文件系统的结构和布局)
  • 书籍的总数和可用数(文件系统的空间使用情况)
  • 书籍增加或删除的基本规则(文件系统如何分配空间) 等等。
  • 所以:
    当你进入图书馆,首先需要查阅目录,了解这个图书馆的整体情况。
    同样,当操作系统访问文件系统时,首先需要读取超级块,以了解文件系统的全局信息。
    通过超级块,操作系统知道如何组织和管理文件系统,像添加删除文件,分配空间等。
    可以看出超级块非常重要,它为操作系统提供了打开并使用这个“文件系统图书馆”所需要的全部信息。
    所以简单来说,超级块就像图书馆的目录,记录了文件系统的全局信息,帮助操作系统理解和管理文件系统。
  • 空闲空间管理
    • 可以把文件系统比作一个储物柜,里面有许多不同大小的抽屉。
    • 这些抽屉可以用来存放文件。当需要存储新文件时,就需要找到大小合适的抽屉来存放。
      那么空闲空间管理就好比是一个记录,跟踪哪些抽屉是空的,大小是多少。
      当你要把新的文件放入柜子时,可以查看记录,很快找到合适大小的空抽屉来使用。
    • 如果没有空闲空间管理的记录,每次要放新文件时,你就需要一个一个抽屉打开查看能不能放得下,十分低效。
    • 同样,文件系统中也需要空闲空间管理来跟踪空闲的存储空间,以方便快速找到合适的空间存放新文件。
    • 一般来说,文件系统会以一定的粒度来划分空闲空间,并用位图等数据结构跟踪空闲块。
    • 所以简单来说,空闲空间管理就像储物柜的空位记录,它帮助文件系统快速高效地找到空闲空间以存储新文件。
  • i结点
    就是iNode结点,包含了各种文件相关属性信息(也称元数据)。
  • 根目录文件和目录
    • 在Windows里,C盘可以视为一个分区,C盘下的文件夹就相当于这个分区的目录。
      例如C盘下有一个Windows文件夹,这个Windows文件夹就是C盘根目录下的一个子目录。
      再比如在Windows文件夹里面,有个System32文件夹,那么这个System32就是Windows目录下的一个子目录。
    • 又如在System32文件夹里面,有个drivers文件夹,那么drivers文件夹就是System32的子目录。
      也就是说,C盘本身可以视为根目录,里面的Windows文件夹是C盘的一个子目录,System32是Windows目录的子目录,drivers是System32的子目录。
    • 通过这种目录树的逻辑组织,文件系统可以层层包含子目录和文件,就像文件夹套娃一样。
      我们通过从根目录开始,一级一级地打开子目录,就可以找到需要的文件,非常方便管理。
    • 所以在Windows的文件系统中,根目录代表一个磁盘分区,子目录代表当前目录下的子文件夹,它们一起构成了文件资源的目录树结构。
      • 另外,文件,emmm,就是文件,没什么解释的。

磁盘的寻址方式

磁盘是典型的块设备,硬盘分区被划分为一个个的block(块,也叫扇区)。一个block的大小是由格式化的时候确定的,并且不可以更改。
我们将磁盘分成一个个的扇区,如图中蓝色线条组成的三角形一样,又称物理块,我们磁盘的寻址一般以一个扇区(一个块)为单位进行寻址。

在这里插入图片描述

串起来

通过上面的基础知识铺垫,我们现在可以串一串程序究竟是怎么打开一个文件并在后序对文件进行操作的了。

  • 程序运行起来,调用语言相关文件打开函数,或直接使用系统调用。
  • 在打开文件时,VFS层(虚拟文件系统)根据文件路径在磁盘的目录树中找到iNode,如果找到该文件,那么为此文件分配一个文件描述符,维护在进程的文件描述符表中,在当前进程的文件表中创建文件表项,建立起 fd 与 iNode 的映射关系,并记录打开状态。
  • 如果使用的是系统调用则返回文件描述符,如果是语言封装的文件相关函数,那么返回语言规定的返回值,该返回值封装了 fd。比如c语言中的FILE*,该结构体指针就封装了 fd。
  • 打开文件后对文件读写时,通过文件描述符在文件表中查找记录,进行偏移定位,找到对应的iNode,通过提取iNode中具体的文件所在逻辑块位置,通过块位映射表(维护了逻辑块与物理块的映射关系,类似与虚拟内存的页表)最终转换为对具体物理块的操作。
  • 关闭文件时,文件表项被删除,资源释放。

用通俗的语言解释上下层关系:

  • 把文件系统比作一个组织机构,不同层次负责不同的工作:
  • 底层员工(inode)负责文件存储和元信息。
  • 中间管理(文件表)负责跟踪当前正在处理的文件项目。
  • 高层主管(VFS)与外界交流,接受任务请求。
  • 当一个新任务来时,主管交给管理层处理,管理层创建一个项目跟踪记录。
  • 员工根据记录去实际操作和处理项目,完成时汇报管理层。
  • 管理层最后将项目记录删除,汇报主管任务完成。
  • 这样不同层级最终协同完成对文件操作的管理。

几个关于文件系统的疑问

我们删除文件,是直接对磁盘上的文件清理了吗?

不,我们只是对文件的iNode进行了处理。因为有文件系统这一层抽象,我们的计算机是通过文件系统来管理文件的,那么我们也就只需要在文件系统中要删除的文件所对应的iNode删掉就好,没有了索引,也就相当于不存在,下一次别的文件就可以直接覆盖磁盘上的这一块区域,也是效率上的提示。

我们常说的格式化,比如格式化硬盘,什么意思

实际上就是对硬盘进行初始化,加载文件系统,向该磁盘分区写入文件系统的管理属性信息。这里我们也可以看到,其实每个分区都会有一个单独的文件系统进行管理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/86991.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】BLIP: 用于统一的视觉-语言理解和生成的引导式语言图像预训练

BLIP: Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generation BLIP&#xff1a;用于统一的视觉-语言理解和生成的引导式语言图像预训练 论文&#xff1a;https://arxiv.org/abs/2201.12086 代码&#xff1a;https://github.…

NotePad++ 在行前/行后添加特殊字符内容方法

我们在处理数据时&#xff0c;会遇到需要在每行数据前面、后面、开头、结尾添加各种不一样的字符 如果数据不多&#xff0c;我们可以自己手动的去添加&#xff0c;但如果达到了成百上千行&#xff0c;此时再机械的手动添加是不现实的 这里教给大家如何快速的在数据每行的前后…

QT 绘画功能的时钟

.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent> #include <QDebug> //信息调试类 #include <QPainter> #include <QPixmap> //图像引擎类 #include <QTime> #include <QTimer> …

秋招准备--基础知识复习--系统编程

lab1 进程 定义 进程的定义是操作系统中资源分配的基本单位&#xff0c;是程序的执行实体。具体地来分析这个定义的一体两面&#xff1a; 在资源分配方面&#xff0c;每个进程都有虚拟的进程空间&#xff0c;其中包括代码区&#xff0c;全局静态区&#xff0c;BSS区&#xff…

一文读懂 Redis 缓存系统

【摘要】本文介绍了Redis缓存原理、详细解析了缓存模型、缓存一致性和缓存异常场景。 【作者】李杰&#xff0c;专注于Java虚拟机技术、云原生技术领域的探索与研究。 尽管&#xff08;关系型&#xff09;数据库系统 (SQL) 带来了许多出色的属性&#xff0c;例如 ACID&#x…

Spring Boot Actuator使用指南

什么是 Spring Boot Actuator&#xff1f; Spring Boot Actuator 是 Spring Boot 提供的一种生产级别的特性&#xff0c;它可以帮助我们监控和管理 Spring Boot 应用&#xff0c;比如健康检查、审计、统计和 HTTP 追踪等。所有这些特性可以通过 JMX 或者 HTTP endpoints 来访问…

Linux系统编程——总结初识Linux(常用命令、特点、常见操作系统)

文章目录 UNIX操作系统&#xff08;了解&#xff09;Linux操作系统主要特征Linux和unix的区别和联系什么是操作系统常见的操作系统Ubuntu操作系统Ubuntu安装linux下的目录的类型(掌握)shell指令shell指令的格式文件操作相关指令系统相关命令网络相关命令其他命令软件安装相关的…

duilib 进阶 之 list 容器使用 及扩展

目录 一、list控件 1、选中事件的例子 2、子项目为简单容器时赋值 1)、直接样式文件里赋值

leetcode Top100(16)缺失的第一个正数

给你一个未排序的整数数组 nums &#xff0c;请你找出其中没有出现的最小的正整数。 * * 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 * * * 示例 1&#xff1a; * * 输入&#xff1a;nums [1,2,0] * 输出&#xff1a;3 * 示例 2&#xff1a; * * 输入…

【算法】排序——插入排序及希尔排序

目录 前言 一、排序的概念及其应用 1.1排序的概念 1.2排序的应用 1.3常见的排序算法 二、插入排序的实现 基于插入排序的优化——希尔排序&#xff08;缩小增量排序 个人主页 代码仓库 C语言专栏 初阶数据结构专栏 Linux专栏 LeetCode刷题 算法专栏 前言 这…

js for循环设置循环变量和循环体内部是两个单独作用域

参考文章 for 循环设置循环变量的那部分是一个父作用域&#xff0c;而循环体内部是一个单独的子作用域。 for (let i 0; i < 3; i) {let i abc;console.log(i); } // abc // abc // abc上面代码正确运行&#xff0c;输出了 3 次abc。这表明函数内部的变量i与循环变量i不…

多进程编程- POSIX命名信号量(named semaphore)

POSIX命名信号量是POSIX标准下的一个进程间同步原语&#xff0c;允许多个进程共享同一个信号量&#xff0c;从而实现进程间的同步和通信。这与无名信号量不同&#xff0c;无名信号量主要用于线程之间的同步&#xff0c;而不是进程之间。 命名信号量是“命名”的&#xff0c;因…

工作、生活常用免费api接口大全

手机号码归属地&#xff1a;提供三大运营商的手机号码归属地查询。全国快递物流查询&#xff1a;1.提供包括申通、顺丰、圆通、韵达、中通、汇通等600快递公司在内的快递物流单号查询。2.与官网实时同步更新。3.自动识别快递公司。IP归属地-IPv4区县级&#xff1a;根据IP地址查…

Kubernetes集群+Keepalived+Nginx+防火墙 实例

目录 实验前期规划 1.拓扑图结构 2.实验要求 3.实验环境规划 一.kubeadm 部署 K8S 集群架构 1.环境准备 2.三个节点安装docker 3.三个节点安装kubeadm&#xff0c;kubelet和kubectl 4.部署K8S集群 &#xff08;1&#xff09;初始化 4.部署K8S集群 &#xff08;1&am…

Linux硬链接、软链接

硬链接是一个目录条目(在基于目录的文件系统中)&#xff0c;它将一个名称与一个文件关联起来。因此&#xff0c;每个文件必须至少有一个硬链接。为文件创建额外的硬链接可以使该文件的内容可以通过额外的路径访问(即通过不同的名称或在不同的目录中)这会导致别名效应(alias eff…

java微服务 Dubbo面试题/SpringCloud面试题

java微服务面试题 Q:为什么要用微服务&#xff1f;微服务有哪些优势&#xff1f; 单体应用把所有功能都堆放在一起&#xff0c;改动影响大&#xff0c;风险高。 微服务具有以下优势&#xff1a; 针对特定服务发布&#xff0c;影响小&#xff0c;风险小&#xff0c;成本低。 频…

C++:C++哪些时候用到const

声明常量&#xff1a;使用const关键字定义一个常量&#xff0c;不允许对其进行更改。例如&#xff1a; const int PI 3.1415926;修饰函数参数&#xff1a;加上const限定符可以确保函数不会修改传入的参数值。例如&#xff1a; void print(const int num) {// num不能在函数内…

【C++】异常处理(一)

这篇文章介绍下 C 的异常处理。 讨论一种最为常见的出现异常的情况&#xff0c;即 0 不能作为除数。为此&#xff0c;我们将自定义一个除法&#xff1a; #include <iostream>using namespace std;int divide(int a, int b) {return a / b; }int main() {int a 3, b 0…

【一、虚拟机vmware安装】

安装虚拟机 下载 官方下载地址&#xff1a;https://www.vmware.com/cn.html 大概流程就是&#xff0c;最重要的事最后一步

【openwrt学习笔记】miniupnpd学习笔记

目录 一、参考资料二、upnp基本概念三、miniupnpd3.1参数说明3.1.1 config upnp 的配置参数表3.1.2 config perm_rule 许可设置配置参数表 3.2 windows上使用miniupnpc工具3.3 关于开启upnp功能后无法添加端口 四、其它知识补充4.1 NAT4.1.1 NAT概念4.1.2 NAT的分类 4.2 NAT穿透…