【Linux系统编程】文件系统

news2024/11/24 9:16:45

介绍:

        文件系统是操作系统中负责管理和存储文件信息的软件结构,它组织和管理磁盘上的文件和目录,并定义了文件的存储结构。

        Linux文件系统采用树状结构,只有一个根目录(用“/”表示),其中含有下级子目录或文件的信息。子目录中又可以包含更多的子目录或文件,这样一层一层地延伸下去,构成一棵倒置的树。


磁盘

        进程打开文件,没有打开的文件在磁盘上保存,并通过文件系统进行管理。在笔记本电脑(或任何计算机)中,C盘和D盘(以及其他可能的盘符,如E盘、F盘等)并不是物理硬件本身,而是硬盘或固态硬盘(SSD)上的逻辑分区或卷。这些分区或卷在操作系统中被识别为不同的驱动器或“盘”,并分配了不同的字母标识符(如C:、D:等)。

        在磁盘中,文件属性对应的数据存储在结构体inode中。它包括文件类型、大小、权限、时间等等,但inode没有包含文件名,因为文件名不属于文件属性。Linux中使用ll -i 指令可查看文件或目录的inode。这里要说明的是系统管理文件的属性大小是固定的(内容与属性分开存储),因为属性的类别是一样的,只不过每个类别的内容不一样,即inode大小通常固定,大小通常是128字节,有些的文件系统中可以设置为256字节。


inode结构

inode管理

        inode结构体准确来说记录了文件的元数据信息,是唯一标识文件系统中的每一个文件的。元数据包括文件属性,其中,一个inode可以有多个文件名,但一个文件名只能对应一个inode。

        那么inode具体是如何怎么管理文件的呢?在同一文件系统中,每个inode结构中都存储着一个唯一的编号,即inode编号。操作系统使用inode编号来识别不同的文件,而不是文件名来识别文件。系统都是通过inode来对文件进行操作的。我们通常使用ls -i命令可以查看文件的inode号。

        通常,每个文件或目录都有一个唯一的inode与之关联(一个inode对应一个文件名的情况),但是有些特殊情况下(一个inode对应多个文件名的情况下),多个文件名(文件名也叫硬链接)可能对应同一个inode。这种情况下,所有的这些文件名都会引用同一个inode,并且具有相同的inode编号。这意味着这些文件实际上是同一个文件的不同名称,它们共享相同的文件内容和元数据。需要注意的是,虽然多个文件名可以指向同一个inode,但一个inode通常只能与一个文件内容相关联。也就是说,你不能有两个不同的文件内容共享同一个inode。如果你尝试这样做,系统通常会创建一个新的inode来存储新的文件内容。

        inode在文件系统中存储在磁盘文件系统的分区里的inode表中,即inode Table。

inode链接和inode表

        inode中包含一个链接数(link count),表示有多少个文件名(即硬链接)指向这个inode。当创建一个新的硬链接时,链接数会增加一个;当删除一个硬链接(无论是通过rm命令还是删除目录项)时,链接数会减少一个。当链接数减少到0时,inode会被标记为可回收,对应磁盘空间上的文件内容会被删除。

        这里我们说明一下文件名。Linux系统中,inode本身并不直接存储文件名,而是存储了文件的元数据信息。文件名实际上是与inode关联的目录项中的一部分,具体来说文件名与相应的inode编号关联,它们保存在文件系统的目录结构中。文件名只是一个标识符,真正的文件内容和属性是通过inode来访问的。至于文件内容,inode是通过内部数据块指针来指向的,inode中的数据块指针指向文件内容在磁盘上的存储位置。这些指针是文件系统定位文件内容的关键,不同的文件会有不同的数据块指针分布。

        文件=“文件属性”  + “文件内容”。文件的一系列信息基本都是通过inode间接引出的。总的来说,当系统对文件进行操作时,首先会找到对应inode编号,找到inode编号后就能在inode表(inode Table)中找到inode,找到inode后,就能拿到inode里面对应的文件数据块。


磁盘文件系统

        上图中是磁盘文件系统的分区(如同windows下的C盘、D盘等)。磁盘是典型的块设备,硬盘分区(如上图)被划分为一个个大小固定的block。一个block的大小是由格式化的时候确定的,不可以更改。其中上图的 Boot Block 是启动块。上图的Block group 0......Block group n是一个分区中对应的很多分组。每个分组中又划分了许多个块(Block),下面我们依次来分析这些块。

        inode Table:inode表。从逻辑和概念上讲,可以将inode表(inode Table)视为一个数组,其中每个inode的编号可以看作是这个数组的一个下标。通过inode编号,可找到文件在磁盘上的存储位置。具体有多少个inode是系统根据分区早早分配好的。

        inode Bitmap:inode位图。我们不能确定inode Table(inode表)中的inode是否被占用,系统是通过inode Bitmap(inode位图)使用每个bit来表示一个inode是否空闲可用。比特位的位置表示第几个inode,比特位的内容表示该inode是否被使用(0表示未占用,1表示已被占用)。

        Data blocks:数据块。存放文件内容。Data blocks是由无数的块(block)组成,每个块大小一般固定约4KB,存放文件内容时从左到右依次使用块存储,且每个块都有自己的编号。这些块的数量也是系统根据分区就已分配好的。

        Block Bitmap(Block位图):块位图。记录着Data Blocks中哪个数据块已经被占用,哪个数据块没有被占用。Block Bitmap原理与inode Bitmap一样,都是通过相应编号(即:数组下标)标识是否被用过。

        下面问题来了,系统如何知道哪一个inode和哪一个Date blocks(即文件内容)是对应关系呢?inode内部里面包含了block整型数组,此数组记录了对应文件数据块的编号。即通过inode中的block数组即可找到对应的文件内容。

        例如:当我们新建一个文件并写入文件内容时,在上面四种块结构中,系统首先会在inode Bitmap查找没有使用的位图,这里会通过计数从左到右开始遍历,直到找到未占用的inode(即数组下标为0),然后会在inode Table中进行索引(如在inode位图中找到的是10,直接在inode表中找到第十个inode),接下来会使用inode属性结构体把文件对应的字段填入进入,之后会把这个inode结构体按照二进制形式拷贝到inode Table中对应的inode块中(如拷贝到inode表中第十个inode里),这里属性就有了,至于文件内容的填充取决于内容的大小,若文件内容大小估计使用1个块,即内容小于4KB,这里会分配一个块进行填充,分配的块号会被写入block整型数组中,对应的Block Bitmap也会被修改成1。当清除文件时,这里先找到inode,将对应的inode Bitmap和Block Bitmap位图号从1变成0即可。也就是说删除文件时不会删除inode的内容以及block的内容,只需把对应的两个位图清掉即可。

        现在我们都明白,查找一个文件就是通过inode编号来查找,那么具体是如何快速通过inode编号找到对应的文件呢?我们要先明白inode是在一个分区中唯一的,不是在一个分组中唯一的。倘若在第一个分组中分配10000个inode,即起始值是1,那么第二个分组中分配的inode就会从10001开始,即起始值是10001,后面同理。当系统给文件分配inode编号时,若在一个分区中的第n个分组中对应inode Bitmap找到第m个bit为0,即找到了inode Table中的第m个inode,那么在往第m个inode填充属性时,填充inode字段里的inode编号其实是 “inode Table中的起始偏移量” + m。拿到对应的inode编号查找具体的inode时,首先会在每个分组中分配的inode范围中找到具体对应的分组,然后再用inode编号减去对应分组下的起始inode偏移量就能找到对应的inode Bitmap中的位号和inode Table中具体的inode号,当查到对应inode Bitmap中的位号属于存在位号时,就会在对应的inode Table中找到具体的inode获取属性信息。文件内容同理,只不过在inode对应的block整型数组字段中,眏射的块并不是全部对应的文件内容,而是采用直接索引、间接索引和三级索引或更多的索引通过块来引出,块中存放着指向对应块的指针,指向对应块,但大多数情况下(文件内容较小的情况)block是直接眏射文件内容的。

        Group Descriptor Table(GDT):块组描述符,描述块组属性信息。它也是一个结构体,包含了该分组的具体信息,如inode的数量、空闲inode的数量、数据块的数量、空闲数据块的数量等。因此,每个分组中的GDT大概率都是不一样的,GDT被损坏会导致这个分组被破坏。

        Super Block(超级快):超级块包含了关于文件系统的全局信息,存放文件系统本身的结构信息,包括每个分组的描述块的位置和大小。通过读取超级块,系统可以定位到每个分组的描述块。记录的信息主要有:bolck 和 inode的总量, 未使用的block 和 inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了,因此,虽然整个文件系统的关键信息只需要一个Super Block就足够了,但是系统还会在个别的分组中加入Super Block,而不是全部分组中加入,这样既保证了某个Block Group的Super Block数据损坏,文件系统仍然可以通过其他Block Group中的Super Block备份信息来恢复,也能保证跟新Super Block时的效率问题。总的来说,系统只要拿到了Super Block就可对此分区进行管理。

        Boot Block块比较特殊,它并不是所有分区都拥有的,主要功能是协助系统了解磁盘的分区情况,这里了解即可。

        上面的分区情况就是文件系统下的情况,即一个分区对应一个文件系统。平常电脑上磁盘的格式化本质是向指定的分区中写入全新的文件系统(上面介绍的文件系统属于ext2版本,其它版本的文件系统可能有所不同,但原理都是一样的,只不过增添了一些日志内容)。那么系统如何管理多个文件系统?一个分区一个文件系统,每个分区中的核心是Super Block,里面包含了该分区下的所有属性。系统只需拿到每个分区下的Super Block,然后将它们用链表的形式连接起来即可。总的来说,系统对分区的管理就是对Super Block的管理;系统对多个文件系统的管理就是对链表的管理。


文件名

        了解文件名,首先我们要先了解下目录。任何一个普通文件一定在一个目录中,而目录也是文件,也通过inode管理,但目录的内容放什么呢?目录的数据块中存放的是文件名和inode编号的眏射关系。当在目录中查找一个文件名时,系统能够根据文件名来找到对应的inode。当在目录中创建一个新文件时,将对应的inode和数据块填充之后,系统会拿到对应文件的inode编号的眏射关系和文件名再写入到文件目录内容里面。文件权限的限制功能对应的是以上原理。

        当我们在一个目录中创建一个文件时,若该目录没有写权限,将不能在该目录下创建文件,因为创建文件时需要将该文件的inode编号的眏射关系和文件名再写入到目录内容里,若没有写权限就无法写入。查找文件时同理,若是无法读取文件名与inode编号的眏射关系进而将无法使用对应的功能。删除一个文件时需要去除目录里面的文件名与inode编号的眏射关系,这也需要修改目录内容,这也就是为什么去掉写权限将无法删除文件。其它权限功能同理。

        这里有一个问题,当查找一个文件,我们需要拿到该目录的内容,目录内容在数据块中存储的,要想拿到该目录的内容就要拿到该目录的inode编号,要想拿到该目录的inode编号就要拿到该目录的目录的内容,这样就出现了 “鸡生蛋,蛋生鸡” 的问题,最终会在根目录(“/”)下终止。因此,在系统层面上,当查找一个文件时,在内核中都要逆向的递归般得到根目录,然后系统再从根目录下诼渐往下查找,进行路径解析,直到找到指定文件。查找的过程中系统会把此路径信息缓存下来,方便我们在此路径下对不同目录或文件进行快速切换或操作。

        当我们拿到inode后,又该如何在分区中寻找inode呢?这里我们要先明白挂载的概念。一个被写入文件系统的分区,要被Linux使用,必须要先把这个具有文件系统的分区进行 “挂载” 。“挂载” 是把一个文件系统所对应的分区,挂载在对应的目录中,文件系统的数据结构与目录的数据结构之间通过指针关联,访问分区下的文件系统都是要通过目录来访问。在Linux中使用 df -h 命令可查看。比如我们使用云服务器时,上面左侧Filesystem表示文件系统,服务器上的云盘只有一块,即分区只有一个,叫做/dev/vda1,它被挂载到根目录上。因为只有一个分区,所以从根目录下的所有内容都会在这一个分区中,也就是说要访问此分区,只要保证我们在根目录下,就能访问当前对应的分区。倘若我们系统中存在多盘的情况下,即存在 /dev/vda1、/dev/vda2、/dev/vda3...,这时需要时用mount命令将分区挂载到Linux下的一个文件夹中,从而将分区和该目录联系起来,从此往后只需访问这个文件夹就相当于访问该分区了。挂载好之后使用 df -h 指令可查看到此挂载后的目录,当进行路径切换后,就可能从一个分区切换到另一个分区了,本质就是从一个目录切换到另一个目录。总的来说,分区的访问就是通过所挂载的路径访问的,我们也可使用Linux下的命令来创建文件系统,实现挂载,然后cd到指定的目录后,我们就是在访问这个分区。

        当查找指定的文件时,系统会根据路径最前缀的目录优先判断出该文件在具体哪个分区下,然后根据路径不断往下解析将会找到所有对应的inode。对于路径若不详细说明,系统会默认在当前路径下。最终将指定的文件inode导入内存中,通过进程打开。

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

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

相关文章

C++ 函数高级——函数的默认参数

函数默认参数 在C中,函数的形参列表中的形参是可以有默认值的 语法:返回值类型 函数名 (参数 默认值){ } 示例: 正确代码: 运行结果:

黑马|最新AI+若依 |初识项目

本章主要内容是: 1.快速搭建了若依前后端项目在本地 2.实现了单表的增删改查快速生成 文章目录 介绍1.若依介绍2.若依的不同版本3.项目运行环境 初始化前后端项目1.下载若依项目2.初始化后端a.把表导入到数据库中b.更改application.yml文件 3.初始化前端a.安装依赖…

java集合(2)

目录 一. Map接口下的实现类 1. HashMap 1.1 HashMap常用方法 2. TreeMap 2.1 TreeMap常用方法 3. Hashtable 3.1 Hashtable常用方法 4.Map集合的遍历 4.1 根据键找值 4.2 利用map中的entrySet()方法 二.Collections类 1.Collections类中的常用方法 三. 泛型 1. 为什…

大连外贸建站公司wordpress主题模板

Robonaut萝卜纳特WP外贸站模板 适合用于工业机器人公司出口做外贸搭建公司官方网站使用的WordPress模板。 https://www.jianzhanpress.com/?p7091 优衣裳WordPress外贸建站模板 简洁的wordpress外贸独立站模板,适合服装、衣服、制衣外贸公司搭建公司官方网站使用…

shark云原生-日志体系-filebeat高级配置(适用于生产)-更新中

文章目录 1. filebeat.inputs 静态日志收集器2. filebeat.autodiscover 自动发现2.1. autodiscover 和 inputs2.2. 如何配置生效2.3. Providers 提供者2.4. Providers kubernetes2.5. 配置 templates2.5.1. kubernetes 自动发现事件中的变量字段2.5.2 配置 templates 2.6. 基于…

人工智能系列-Pandas基础

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” Pandas简介 Pandas是Python语言的拓展程序库,用于数据分析。 Pandas是一个开放源码,BSD许可的库,提供高性能,易于使用的数据结…

vuepress创建步骤

背景 记录vuepress配置步骤,以便下次使用快速上手。 读此文章之前默认您已经学会了创建vuepress项目。vuepres快速开始 最终成品 doc.jeecgflow.com 配置步骤 创建.vuepress 目录。 你的文档目录下创建一个 .vuepress 目录。 创建.vuepress/config.js module.e…

【IMU】 确定性误差与IMU_TK标定原理

1、确定性误差 MEMS IMU确定性误差模型 K 为比例因子误差 误差来源:器件的输出往往为脉冲值或模数转换得到的值,需要乘以一个刻度系数才能转换成角速度或加速度值,若该系数不准,便存在刻度系数误差。 T 为交轴耦合误差 误差来源:如下图,b坐标系是正交的imu坐标系,s坐标系的三…

spring-ai 下载不了依赖spring-ai-openai-spring-boot-starter

第1坑:配置第三方仓库不生效, 提示在阿里云仓库没有找到 spring-ai-openai-spring-boot-starter 第2坑:升级jdk17后,springboot项目启动报错 Internal error (java.lang.reflect.InaccessibleObjectException): Unable to make pr…

第10章:网络与信息安全

目录 第10章:网络与信息安全 网络概述 计算机网络概念 计算机网络的分类 网络的拓扑结构 ISO/OSI网络体系结构 网络互联硬件 物理层互联设备 数据链路层互联设备 网络层互联设备 应用层互联设备 网络的协议与标准 网络标准 TCP/IP协议族 网络接口层协…

【若依前后端分离】通过输入用户编号自动带出部门名称(部门树)

一、部门树 使用 <treeselect v-model"form.deptId" :options"deptOptions" :show-count"true" placeholder"请选择归属部门"/> <el-col :span"12"><el-form-item label"归属部门" prop"dept…

C++ 什么是虚函数?什么是纯虚函数,以及区别?(通俗易懂)

&#x1f4da; 当谈到虚函数时&#xff0c;通常是指在面向对象编程中的一种机制&#xff0c;它允许在派生类中重写基类的函数&#xff0c;并且能够通过基类指针或引用调用派生类中的函数。 目录 前言 &#x1f525; 虚函数 &#x1f525; 纯虚函数 &#x1f525; 两者区别…

IntelliJ IDEA教育版在Windows电脑中的下载、安装方法

本文介绍IntelliJ IDEA软件Community&#xff08;社区版&#xff09;在Windows操作系统中的下载、安装、运行与使用方法。 IntelliJ IDEA软件是一款由JetBrains公司开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要用于Java语言的开发&#xff0c;但同时也支持其…

win7系统快速安装python

下载安装包 建议选择python3.8左右的&#xff0c;我下载的是3.7.8&#xff0c;最新版本的pythonwin7可能不支持 python网址 下拉寻找 安装python 1.双击安装包 更换完地址选择安装(install) 安装完成后点击close即可 测试是否安装成功 1.winr快捷键打开黑窗口输入cmd …

【Linux】线程(轻量级进程)

目录 一、线程概念 二、线程特性 2.1 进程更加轻量化 2.2 线程的优点 2.3 线程的缺点 2.4 线程的异常 2.5 线程用途 三、进程和线程 四、线程控制 4.1 包含线程的编译链接 4.2 创建线程 4.3 获得线程自身的ID 4.4 线程终止 4.5 线程等待 4.6 线程分离 4.6 线程…

Redis官方可视化管理工具

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl RedisInsight是一个Redis可视化工具&#xff0c;提供设计、开发和优化 Redis 应用程序的功能。RedisInsight分为免费的社区版和一个付费的企业版&#xff0c;免费版具有基本…

thingsboard v3.7 win编译相关问题记录

遇到的问题总结 node\yarn 相关版本问题 3.7 开始需要 JDK17 ui-ngx 模块 yarn 相关问题报错 报错信息 [INFO] Downloading https://github.com/yarnpkg/yarn/releases/download/v1.22.10/yarn-v1.22.10.tar.gz to D:\soft\maven\com\github\eirslett\yarn\1.22.10\yarn-1.2…

ASP.NET Core----基础学习04----Model模型的创建 服务的注入

文章目录 1. 创建Models文件夹&#xff0c;3个文件的内容如下&#xff1a;&#xff08;1&#xff09;模型的创建&#xff08;2&#xff09;服务的注入 1. 创建Models文件夹&#xff0c;3个文件的内容如下&#xff1a; &#xff08;1&#xff09;模型的创建 模型的基础类Student…

Apache Hadoop完全分布式集群搭建指南

Hadoop发行版本较多&#xff0c;Cloudera版本&#xff08;Cloudera’s Distribution Including Apache Hadoop&#xff0c;简称CDH&#xff09;收费版本通常用于生产环境&#xff0c;这里用开源免费的Apache Hadoop原始版本。 下载&#xff1a;Apache Hadoop 版本下载&#x…

[Unity入门01] Unity基本操作

参考的傅老师的教程学了一下Unity的基础操作&#xff1a; [傅老師/Unity教學] Unity3D基礎入門 [華梵大學] 遊戲引擎應用基礎(Unity版本) Class#01 移动&#xff1a;鼠标中键旋转&#xff1a;鼠标右键放大&#xff1a;鼠标滚轮飞行模式&#xff1a;右键WASDQEFocus模式&…