文件系统超级详解,彻底理解文件到底是怎么回事~

目录

一、磁盘

1、磁盘物理结构

2、了解磁盘存储结构

3、操作系统如何对磁盘管理

二、文件系统

(1)超级块

(2)格式化

(3)系统如何找到文件

(4)间接映射是什么?

(5)目录内文件名不可重复

(6)文件增删查改本质

(7)回收站的本质

(8)文件路径的本质

(9)打开、关闭文件的本质


在进程部分,我们把被打开文件说明白了。(博主的其他关于进程的文章)
可是,有被打开的文件,就有没有被打开的文件。
那么没有被打开的文件在哪里?
打开文件和没有打开文件有什么区别?
打开文件的本质是什么?
没有被打开的文件在哪里?
磁盘是什么?
磁盘的结构是怎么样子的?
磁盘又是如何管理数据的?
我们找到文件使用路径,路径的本质是什么?
为什么是路径而不是其他的方法?例如说编号?
那么操作系统是怎么通过路径找到文件?
操作系统和磁盘是如何合作的?
文件的增删查改,是怎么做到的?
删除文件,发生了什么?
创建文件,又发生了什么?
修改、查找文件,又发生了什么?
什么叫做文件格式化?
文件格式化的本质是什么?
我们的C盘、D盘是什么?
为什么有C盘、D盘等?
回收站是怎么回事?
我把删除到回收站,文件就真的被删除了吗?
如果我不小心删除了文件,怎么办?
为什么能够找回?
怎么找?
如果找到不到,又为什么找不到?
.....

 

本文章,将回答上述问题,让同学们对文件、操作系统、软硬件工作、程序、数据等有一个更加系统、深刻的认识和理解。在这个过程中,请同学们跟着我充分发挥想象力,我们每一个都是天生的想象家!

一、磁盘

1、磁盘物理结构

一般磁盘区分:桌面级磁盘,民用;企业级磁盘,企业

现在的笔记本用的都是固态硬盘,因为电子结构比机械结构快。但是为什么还用磁盘?便宜。

2、了解磁盘存储结构

磁盘是一个机械结构,而且是外部设备,所以速度慢
磁盘读写的基本单位是扇区:一般是512字节 / 4KB
1片 = n 磁道
1磁道 = m 扇区

如何找到指定位置扇区?
先找到磁头(Header) -> 找到指定磁道 / 柱面(Cylinder) -> 找到指定扇区(Sector)
所以,在硬件找到扇区的方案叫做CHS地址法
盘片的旋转:为了找扇区
磁头的左右移动:为了找磁道
文件存储到磁盘中,其实就是在磁盘中占有几个扇区的问题

3、操作系统如何对磁盘管理

需要对磁盘的存储进行逻辑抽象
从磁带入手
磁磁带会转动,在转动的过程中
把磁带从圆形转化为一个长条的线性
再线性读取
于是,磁带这个存储结构,经过一定的运动模式之后
就从圆形结构转化成了线性结构

所以,从这个角度出发
同样的道理,
我们的磁盘和磁头,在运动的时候,会有顺序的经过一个一个的扇区
然后我们将这些被顺序经过的扇区连接在一起
于是就构建了一个线性结构,
这个线性结构,是由一个个紧挨着的扇区的组合
为了方便理解,我们将每一个扇区的存储大小视为相等的
(实际上是不相等的,但是方便理解)
那么,一个线性结构,每一个节点的大小都是一样大的
我们就可以将之抽象为一个数组!
这个数组的基本单位是扇区的大小
数组的长度,是N个扇区(即总的存储结构决定)
没错,在实际的磁盘管理中,就有一个数组是专门来管理磁盘的

这个数组就是:sector disk_array[N]
而数组,对应的就会有下标

可是,我拿到这个下标
我又怎么找到对应磁盘的扇区位置呢?
这就是需要一定的映射计算
其实也很简单
假设一个面有1000个扇区,10个磁道,每个磁道有100个扇区
现在有一个数组的下标inde,要求找到对应的CHS(柱面Cylinders, Heads磁头, Sectors扇区):

以下是计算过程:

第一,index / 1000  = 面 
第二,index % 1000 = [0,999] temp
第三,temp / 100 = 磁道 C
第四,temp % 100 = 磁道上具体的扇区位置

所以,只要拿到数组的下标,经过计算处理,就能知道磁盘位置

文件 = 很多个扇区的组合,即数组的下标的组合
一般而言,操作系统和磁盘交互的基本单位比实际的扇区单位要大
也就是说一次可能会读取多个连续的扇区
连续的多个扇区,就叫做一个数据块,也就是操作系统一次访问的大小
所以,文件 = 多个数据块的组合

例如,操作系统一次读取的数据块包括8块连续的扇区
此时:
0 * 8 = 0
1 * 8 = 8
2 * 8 = 16
...
0、8、16...这些数字是什么?
是每一个内存块的开始地址
于是,此时操作系统想要读取哪一个数据块,
就可以直接计算得到对应数据块的开始位置
往后读取8个扇区单位大小
就可以得到一整个数据块
同时,这个数据块内部,分成8块扇区
操作系统根据数据块开始位置进行偏移计算
就可以得到对应的扇区

所以,在操作系统看来,
整个磁盘空间,就可以视为一个一个数据块的组合
于是,经过上述对磁盘的组织管理之后
操作系统只要知道磁盘的起始位置 和 磁盘的总容量大小
那么,整个磁盘空间有多少个数据块
每个数据块的块号
以及如何转换到对应的CHS地址
就可以全部计算得到

而上述所描述的数据块的块号
在操纵系统学科中,
还有一个名字
叫做: 逻辑区块地址
也就得到一个叫做  LAB blocks[N]的数组
于是,对磁盘的管理,就变成了对数组的管理
文件 = 很多个LAB地址

但是,磁盘空间很大
整体的管理效率低,且繁冗
所以,需要对磁盘空间进行分区
你的D盘、C盘、E盘,就是分区之后的结果
而分区之后,还有分组
这种管理组织,叫做分治(在Linux文件系统:内容和属性是分开存储的)

二、文件系统

文件组这一层,叫做系统级文件系统

名字介绍
Data Blocks存储实际的文件数据和目录条目,数据区,存放文件内容,占据组内大部分空间
Blocks Bitmap追踪数据块的使用情况(分配或未分配),块位图,记录data blocks中哪个数据块被占用,哪个没有被占用;比特位的位置,表示块号;比特位的内容,表示是否被占用
Super Blocks包含文件系统总体信息(总块数、块大小、自由块计数等)一个组内分散分布
Inode Bitmap追踪i节点的使用情况(分配或未分配),每个bit表示一个inode是否空闲可用,1被占用,0空闲
Inode Table存储文件或目录的所有属性数据(权限、大小、所有者、最近修改时间、数据块地址等)
Block Group Descriptor描述块组结构和状态(块位图、i节点位图、i节点表位置等)

Linux的文件属性是一个大小固定的集合体
即文件属性只有内容的不同,但是文件属性的类别是一样的
其实,也就是一个结构体
在Linux内,这个结构体叫做 inode,一般固定大小128字节(下面展示的是ext2标准)

struct ext2_inode {
    __le16    i_mode;      /* 文件模式 */
    __le16    i_uid;       /* 文件所有者的用户ID */
    __le32    i_size;      /* 文件大小 */
    __le32    i_atime;     /* 最近访问时间 */
    __le32    i_ctime;     /* 最近状态更改时间 */
    __le32    i_mtime;     /* 最近修改时间 */
    __le32    i_dtime;     /* 文件删除时间 */
    __le16    i_gid;       /* 文件所有者的组ID */
    __le16    i_links_count; /* 硬链接数 */
    __le32    i_blocks;    /* 文件占用的块数 */
    __le32    i_flags;     /* 文件标志 */
    union {
        struct {
            __le32  i_addr[12]; /* 直接块指针 */
        } i_data;
        struct {
            __le32  i_addr[3]; /* 指向一级间接块的指针 */
            __le32  i_addr2;   /* 指向二级间接块的指针 */
            __le32  i_addr3;   /* 指向三级间接块的指针 */
        } i_data_ext;
    };
};

inode内部,不包含文件名
在操作系统内核层面,每一个文件结构体内部,都有一个inode number变量
通过此inode编号,标识文件

ll -li:查看inode编号

于是,当我们想找到一个文件时
就可以用inode编号找到对应文件的属性
可是,文件的内容呢?
我怎么知道文件的内容在那些数据块内呢?
为了解决这个问题
在inode结构体内部,有一个int datablocks[N]数组
这个数组,保存该文件所存内容的数据块块号
于是,只要找到文件属性
即inode属性结构体,就同时找到了文件内容
所以,找到一个文件,只要找到文件属性inode结构体对象即可

(1)超级块

超级块不是每一个分组都有的,多个组中有一个
可能是整个组,零星分散几个超级块
这是为了考虑效率
因为,如果某一个区出现问题
那么,事实上超级块也就废了
所以,多几个不如少几个
那么,为什么多个分组同时存在呢?
这是为了避免一个超级块挂掉,
还有其他分组的超级快存在
增加文件系统的稳定性
上述就是一个分组内部的文件系统构架

(2)格式化

同时,在给磁盘分区、分组
再给分组内部划分数据块、位图块、超级块等
要在每一个分区内部分组,然后写入文件系统的管理数据
而这个过程,叫做格式化
所以,格式化的本质,是在磁盘中写入文件系统
所以,一旦格式化,需要清空整个磁盘,再重新载入管理数据
因此,内容数据也就丢了

(3)系统如何找到文件

找文件,都必须找到文件的inode编号
inode编号是以分区位单位整体分配的,而不是分组来分配
两个分区的inode编号可能会重复
所以,inode访问不可以跨区访问

其中super blocks 和 GDT会记录所有分区的起始位置和终点位置
当我们拿到一个inode编号时
首先看是属于哪个分区
然后再用inode编号 - 该分区的起始位置 = 区内分组的位置编号
再用这个组内位置编号到block_BItmap查看
看对应比特位置,是否是1
如果是1,说明这个数据块被占用,是有效的文件
再到inode_Table表中,从前往后找到对应个位置
找到对应的inode属性结构体
就这样,我们就找到了文件的属性,文件的内容

上述所描述的文件系统,叫做ext2
Linux文件系统还有ext3、ext4

(4)间接映射是什么?

对于int data_blocks[N]这个数组来说
是用来记录文件内容所在的数据块的
但是,这个数组的大小是有限的
一般不会太大,例如15个
也就是说,文件的大小只有15个数据块
但是,这明显是不够的
因为我们常见到一些文件的大小远比这个要大的多
如何处理呢?
这个数组前面的部分,会直接指向具体的数据块,
这种内存映射,叫做直接映射
而数组的后面部分,会指向某个数据块
这个数据块的内部,不会存储文件的数据
而是存储其他数据块的地址
于是,文件的数据就可以存储在这些数据块内
这种映射叫做间接映射

(5)目录内文件名不可重复

inode是从那里拿到的?在目录里
我们用户端,访问文件都是使用路径和文件名
并没有用到inode
这就要谈及目录
目录也是文件
而文件就有innode编号
目录文件 = 属性 + 内容
目录的内容,放置的就是inode编号和文件名的映射关系

这就是为什么一个目录内不能建立同一个文件名
找文件的顺序:文件名 -> inode编号

目录的r权限,本质是是否允许我们读取目录的内容
而是目录内容就是文件名和inode编号的映射关系
所以,就意味着不能访问目录下的文件

目录的w权限,新建文件:
其实就是在当前目录内容写入文件名和inode编号的映射关系

(6)文件增删查改本质

如何理解文件的增删查改呢?
根据上述对文件系统的理解

新增文件
当新增一个文件时
这个文件一定是在某个目录下
首先在这个目录下的分区按照循序新增一个inode编号
并建立inode编号和文件名映射关系
然后操作系统根据这个inode编号找到分区内对应的分组
剩下的,就是在inode_table建立inode属性
Block_Bitmap里分配的数据块
在Data_blocks写入数据

查找文件

就是根据文件名和inode编号
从上往下进行查找
修改,只要有inode编号
就可以找到文件的数据位置
想怎么改就怎么改

删除文件
删除并不清理文件内容和属性
只需要在inode_Bitmap把对应的位置置0
就相当于将该文件的内容和属性设置为无效
这就是为什么我们在删除文件时很快的原因
例如删除steam下那些大游戏,说删除就删除
所以,也就是说
在Linux下如果误删了一个文件
是可以恢复的
找到对应的inode_Bitmap
找到对应位置设置为1即可
但是,当你删除一个文件时
就相当于这个文件之前占用的数据块失效了
那么这些数据块就不被不被保护了,即可以被使用
所以,后续你要再进行一些文件操作
就可以使用这些数据块
这些数据块原来的内容,就会被你新写入的数据覆盖
所以,当你误删了一个文件
最好的做法就是什么也不要做
以免覆盖原文件,等待回复
这个inode编号在哪里呢?在删除日志

(7)回收站的本质

那回收站是什么呢?
其实回收站只是一个目录
所以说,删除文件到回收站,只是把这个文件移动到回收站目录下
恢复时,就是把文件移出回收站目录
仅此而已

(8)文件路径的本质

要找到一个文件,得找到文件的inode,怎么找?
先找到对应的目录
在目录下,根据文件名找到inode
可是,目录也是文件
要找到目录文件,也是一样的逻辑
需要找到目录的目录
于是,如此往上推,逆向路径解析
最后就会回到根目录/
所以,这也就是为什么在Linux中
定位一个文件,在任何时候,都要有路径的原因

否则就找不到文件所在位置
因此,每一个文件,都要带有路径信息
那么这个路径,是由谁提供的呢?
由进程提供
是由内核文件系统组织好,由进程交给文件的

同时,inode只在分区内有效
所以,分区之后,要写入文件系统
再挂载到指定目录下
然后我们就可以进入指定目录下,对被挂载的指定分区磁盘进行操作了

可是,每找到一个文件
都要往上回溯解析,很麻烦,效率也低
如果频繁的访问大量的文件,相应的就要解析大量的路径
所以,Linux内核内部会缓存许多已经解析完毕的路径(一些常用路径,其实这就是环境变量!
这样,下一次访问不用再从头解析,提高效率
这个叫做路径缓存
所以内核对一系列解析完毕的路径也进行了管理
怎么管理?
先描述,再组织
对一个被打开的任何文件
都会存在一个struct dentry的结构体
这个结构体中,会存在路径解析的信息

(9)打开、关闭文件的本质

1、文件打开
当一个文件被“打开”时:

分配文件描述符:操作系统为文件分配一个唯一的文件描述符。

检查文件存在性和权限:系统检查文件是否存在,并且用户是否具有适当的权限(如读、写、执行权限)来访问该文件。

读取文件属性数据:操作系统从文件系统中读取文件的属性数据(如文件大小、位置、访问时间等)和文件的物理位置(在磁盘上的位置)。

加载文件结构:文件系统加载文件的结构信息,例如索引节点(inode)或文件控制块(FCB),这些结构包含有关文件的详细信息。

2. 文件关闭
当一个文件被“关闭”时:

刷新缓存:如果文件有未写入的更改(例如,文件的内容被修改过),操作系统将这些更改从内存中的缓存刷新到磁盘上。

释放资源:操作系统释放与文件相关联的资源,例如文件描述符。为其他操作重新分配这些资源。

更新属性数据:操作系统更新文件的属性数据,例如修改时间和访问时间,确保文件的状态最新。

解除文件锁定:如果文件操作过程中被锁定,防止其他进程同时访问,锁定会在文件关闭时解除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二十5画生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值