文件系统
为什么要有文件系统
一个文件如果没有被打开,操作系统应该如何管理这些没有被打开的文件呢?
没有被打开的文件只能放在磁盘文件上面!那么磁盘上面有如此大量的文件!这些大量的文件都应该被管理起来!方便我们随时的打开!——==做这部分的工作的就是文件系统!==
无论是被打开的文件还是不被打开的文件其实都要被文件系统管理
磁盘的结构
要理解文件系统如何管理没有被打开的文件,我们首先就要去了解磁盘
我们要知道磁盘是我们计算机中唯一的机械结构——像是cpu,或者内存其实都是硬件电路构成的!(机械结构是很慢的!而且硬盘还是一个外设)==所以这就注定了磁盘的访问是很慢的!(相比于内存或者cpu)==
在我们日常中的使用正在减少,但是在企业中,磁盘存储依旧是主流(因为相比固态,磁盘的性价比更高,而且存储更加的安全,读写寿命更长)
==磁盘的物理结构==
磁盘的原理和我们日常生活中看到的DVD和VCD是一样的!只不过DVD和VCD一般是单面的!另一面可能印着画
磁盘的磁化
我们都知道,计算机都是使用二进制存储数据的!在硬件上一般都是使用带电或者失去电来表示二进制的,但是其实表示二进制不仅仅是只有这种方式!——例如在网络设备里,可以用信号的有无来表示二进制,或者信号的疏密来表示二进制!——只要是两态的都是可以用来表示二进制的!(计算机只认识01,但是这是指已经对硬件电路做解释了,但是实际上不同硬件表示01的方式是不一样的!)
磁盘之所以叫磁盘——这是因为磁盘上充斥着很多磁化的基本单元
什么叫磁化的基本单元?——其实就是一个磁铁
可以认为每一个盘片上其实都是由一个个的NS极组成的!——可以用N极表示1,S极表示0
==磁头对于特定的某一个位置进行读写的时候本质就是使用电子技术将NS极进行调转!(充磁或者放磁)将0改1就是将N极改成S极==
==磁盘的存储结构==
我们先讨论一面的盘面
知道了一面如何寻找扇区,我们现在讨论一下一摞的盘片如何定位!
==磁盘的逻辑结构==
我们可以先看一下磁带
==那么我们也可以将LBA和CHS算法相互转换==
==对于操作系统使用的是LBA,而对于硬件本身则是使用CHS算法!==
为什么操作系统要使用逻辑地址而不是直接使用CHS算法呢?
便于管理 不想让OS的代码和硬件强耦合
因为存储硬件不止有磁盘,还有例如ssd之类的固态硬盘,或者光碟之类,如果耦合了那么对于每一种存储硬件都要专门写一套代码,这样很不方便!
==磁盘里面保存着各种文件,那么磁盘是如何保存文件的呢?==
虽然访问磁盘的基本单位是512btye,但是依旧很小
假如我们存一个8kb大小的文件,磁盘就要进行8次O每一次IO都要进行一次CHS算法!
每次访问磁盘的时候,一般都要等待磁盘ready——即,操作系统将地址给磁盘,磁盘首先要找(旋转和移动磁头),此时进程进入sleep状态阻塞。等操作系统识别到数据,将数据拷贝进内存里面!最后在唤醒进程。
所以每一次O其实很麻烦!访问外设的效率是很低的!
为了解决这个问题0S的文件系统定制了多个扇区的读取!一也就是说一次不是以512byt为单位的来读取的!而是可以1kb,2kb,4kb(最常用)为基本单位!——哪怕我们只是像读取/修改1个bit,也必须将4kb的内存加载到内存,进行读取或者修改!如果有必要再写回磁盘!
内存一般都是被划分为4kb的空间——内存中也叫做页框
磁盘是没有这个概念的,但是在磁盘中的文件(尤其是可执行文件)是按4kb大小划分好的块!——称之为页帧
(编译器会按照虚拟地址空间大小的方式编好可执行程序,同时还会按照以4kb为单位将数据进行归类例如代码区有40kb,那么就会划分为10个4kb的大小,方便进行加载)
文件系统
==这里我们重点介绍的是分组之后的那的那几个区域==
- super block——保存的是整个文件系统的信息
我们平时经常使用的行为是格式化——格式化本质就是写入文件系统
super block里面有这个分区(不是这个组)里面有几个组!起始块是多少,结束块是多少,分区的健康状态......
super block虽然是在group 0里面,==但是属于整个分区!==——这是为什么?因为在大部分文件系统里面,有一定比例的group里面的都是以super block这个组开头的!(例如group 1,group 2里面也有),所以其实在分组的时候super block不一定是必须的!
那么这是为什么呢?super block很重要!——多份存在意味着多个备份!如果有一天那个常用的super block坏掉了!那么依旧可以从其他的group里面去拷贝一份过来!
- inode table
==在linux里文件 = 内容 +属性!==——这意味着linux的文件内容和文件属性都是分批存储的!
对于保存文件属性linux中有一个重要的概念——==inode==(ext2/3的iNode块的大小是128kb或者ext4的大小是256kb)
总之inode的大小是==固定的!==
一个文件只有一个inode!——而inode里面包含了文件的所有属性!——除了文件名
一般来说100个文件就有100个inode
而为了给不同的inode做出区分!所以每一个inode都有自己的id
在linux里面我们可以通过
ls -li
代码来查看每个文件的inode的id
==inode table 里面就存有了所有(已经使用和没有使用)的inode!==
- data blocks
上面我们说到inode存储的是文件的属性!
而文件内容则是存储在data blocks里面!
data blocks的大小是不固定的!例如一个文本文件和一个1小时的MP4文件,大小就差别很大!或者我们的源文件,当我们不断地写代码,源文件也会不断的增大!所以data blocks的大小是变化的!
所以date blocks保存的是==分组里面==所有文件的数据块!
- inode bitmap
==操作系统是如何找到没有被使用的inode呢?为了方便查找!所以有了inode bitmap==
这是inode的位图!每一个的inode都与位图里面的每一个bit位相对应!
如果被使用了那么bit位就变成1,没有使用bit就变成0
有1000个inode就有对应的1000个bit位
- block bitmap
==和inode一样,如何找到没有用的数据块从而用来存放文件内容,同样也可以用位图来表示==
- group Descriptor Table(块组描述表)
在分组中有多少的inode,多少的block,被使用了多少个,多少个没有被使用。
这些问题虽然可以通过bitmap来计算得到,但是不如直接存起来!
所以有了group Descriptor Table——存储的是对应分组的宏观的属性信息!
==这样子文件系统的各个部分我们都介绍完毕了!==
现在我们来讨论一个问题——==如何查找一个文件呢?==——答案是使用==inode编号!==(inode编号查找文件可以跨组,但是不可以跨分区!因为不同的分区是不同的文件系统的!)
首先去inode bitmap去查对应的bit位,如果是1那么就说明是有效的!
然后再去inode table去拿到文件对应的属性!
==那么重点是文件内容要怎么找呢?——我们都是使用inode编号来查找的?该如何去查找与inode编号有关的数据块呢?==
==创建一个文件的流程也是类似的!==
先去inode bitmap找到没有用过的bit位,将其从0置1
然后去inode table填写文件的属性
如果有数据那么就去data blocks去存储数据
==那么如何删除一个文件呢?==
其实删除一个文件很简单,那就是找到inode对应的位图的bit位,然后将这个bit为从1置为0,这样子就删除完毕了!
那么恢复文件其实也很简单——找到曾经的inode编号,然后在inode bitmap里面找到对应的位图,然后由0置1!(前提是恢复之前最好不要进行任何文件操作!防止数据块被修改!)
最重要的是我们如何得知被删除的inode的id——但是其实操作系统已经帮我们记录了,删除的时候inode的id会被保存进临时日志里面!所以我们可以通过日志来找到
==现在就只剩下最后一个问题!——我们一般查找文件都是使用的是文件名!——而不是inode!那么究竟是怎么使用inode编号的呢?==
首先我们要明确——任何一个文件一定是在一个目录下!,目录本身也是一个文件!目录也有自己的inode,也有自己的数据块!
那么目录的数据块放的是什么呢?——是当前目录下的==文件名和inode的映射关系!==
这就是为什么同一个目录下不能有两个相同的文件名!——因为文件名是一个key值!key值是不能相同的!