文件 = 内容 + 属性,而文件是存储在磁盘上,那么可以理解为磁盘上存储的文件 = 存储的文件内容 + 存储的文件属性。
文件的内容采用的是块式的存储——数据块
文件的属性用
inode
描述在Linux中文件在磁盘上存储,是将内容和属性分开存储的。
我们目前的电脑,搭载的基本上都是固态硬盘(ssd),而老式的电脑,搭载的基本上都是磁盘(机械盘)
固态硬盘IO效率高,但有使用寿命,成本也较大;
机械盘容量大、成本低,效率低于固态硬盘
磁盘是一个永久性存储介质,是计算机中唯一一个机械设备,也是一个外设。我们的计算机全程又叫高速计算的电子计算机器,它是电子的,电信号的传递和机械设备信号的传递,肯定不是一个量级的,这就是它效率相对低的一个原因。
我们小时候接触的光盘,其实就和磁盘有点类似,只不过光盘只有一面是光的,采用的光信息存储;而磁盘如果有一个盘片的话,这个盘片2面都是光的。
盘面高速旋转,然后磁头来回摆动读取数据,这个磁头每面都会有一个磁头(虽然是一面一片,但都是整体移动的),磁头和盘面并不接触,悬浮在盘面。
为什么笔记本不用磁盘了呢?这就是原因之一,我们的笔记本是便携式,要来来回回移动电脑,如果搭载磁盘,那么势必会让磁头和盘面接触到,这样就可能会刮花盘面,而盘面是存储数据的,这样就会导致数据的丢失。
磁盘存储原理:
吸铁石有南北级,我们这里就可以把南北极理解为二进制0
和1
,然后通过某种特性,改变它的南北极,这样就相当于对0
和1
进行修改。
磁盘就可以理解为无数个小的吸铁石构成,磁头扫到磁盘某个位置时,通过电脉冲改变这个南北极,就相当于读数据进行写入。
磁盘被访问的最基本单位为扇区,一般一个扇区的大小为512byte
,要把数据存到磁盘,就得定位一个扇区。
- 定义用哪个磁头
- 哪个一个磁道
- 哪一个扇区
在中这个定位过程中,磁头摆动的次数越多,就说明定位的时间越长。也就是运动的次数越多,效率越低;运动的次数越少,效率越高。
那么对于设计的角度来说,就尽量将有关联的数据放在一起,减少定位寻址的时间
在以前,我们买专辑或者是以前的英语课本,都是以磁带形式录制的,在物理上看,这些磁带是同心圆绕在一起,但如果我们将其全部抽出来,我们在逻辑上可以理解为是线性的。这就有了一个基于扇区的数组,每个扇区都有其对应的下标。
这个28888叫
LBA
逻辑区块地址;转换过来物理地址就叫CHS
我们电脑里面会分多个盘(C盘、D盘、E盘…)来便于我们用户管理不同的数据。
但在系统层面的分区,其实就是将一整块的内容,定义头尾,这样来表示分区:
struct partion
{
int start;
int end;
}
分区之后,系统要管理这整块磁盘的内容就转变成了管理这一块区域,后面区域的管理直接CV
就行。当然了我们分区一般都是按几十几百GB来分的,这几十几百GB也十分的大,系统会继续划分为各个block group
,这个block group
里面就包含了我们的文件系统。
Date blocks
:存文件内容的区域,以块的形式呈现。常见的是4kb
大小 —— 文件系统的块大小这里的意思就是,如果我们创建了一个文件,我们只往里面写一个字节的内容,在文件系统中,都要在分区里面找一个块组申请一个块,这个块的大小是
4kb
。所以访问文件的最小单位就是4kb
inode table
:
inode
:单个文件的所有属性,一般而言大小是128byte
,一个文件一个inode
,每个inode
的编号是唯一的。在Linux用inode
来标识文件,文件属性中,不包含文件名称。#define NUM struct inode { 文件类型 权限 引用计数 拥有者 所属组 ACM时间 inode number; int block[NUM]; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
inode Bitmap
:比特位的位置和inode
编号映射起来,比特位的内容表示inode
是否有效
Block Bitmap
:比特位的位置和块号映射,比特位的内容表示该块有没有被使用我们删一个文件的时候,就不用把块内容清空了,直接将这个块号比特位置空即可(
这就是为什么拷贝大文件会相对慢,而删除一个文件相对快
)。
Group Descriptor Table
:inode bitmap
和block bitmap
用来描述inode
编号和块号是否有效,无法描述这些组里面使用情况,而GDT
就能用来这个组的基本使用情况(用了多少、还剩多少…)
Super Block
:整个分区的基本使用情况,一共多少个组,每组的大小
每组的
inode
数量每组的
block
数量每组的起始
inode
文件系统类型与名称…
这个
Super block
会在block group
里面存在多份,这样是为了防止Super bolck
出现异常导致每个组的边界不清楚,从而导致整个分区全部混乱。
每一个分区在使用之前,都必须提前将部分文件系统的属性信息提前设置进对应的分区中,方便后续使用整个分区或者分组。
- 在新建一个文件的时候,先确定在哪个分区(路径),根据
inode bitmap
分配inode
,然后内容由block bitmap
检查分配块号,然后再将内容填入这个块里面- 删除一个文件的时候,根据
inode
找到属性,先将block bitmap
置空,再将inode bitmap
置空,不需要就块里面的内容清空- 查找文件就是根据这个文件的
inode
找到该文件的属性,再从属性里面找到对应的块
在Linux下,一切皆文件,我们的目录,也属于文件,也有自己的inode
,也要有自己的属性,他的属性我们可以查看,但是内容又是什么呢?
目录数据块里面放的是该目录的文件和对应文件的inode
映射关系,是一个kv
结构。
所以这就是为什么同一个目录下不能由同名的文件,因为这个
kv
的映射;如果我们在这个目录没有
w
写权限,那么就不能创建文件或目录,因为这个文件的名和inode
的映射关系无法写到这个数据块里面;如果没有
r
读权限,我们无法查看这个文件,因为得不到文件的文件名和inode
的映射关系;
我们要找到这个目录,就得由这个目录的目录inode
,所有目录往上走,最后都是根目录\
,所有会一直往上找,找到根目录,然后再往下传inode
。所有访问然后文件,都得有这个文件的路径。
我们有时候访问文件,都是直接访问的,这是因为系统有环境变量,进程也有自己工作的当前目录,所以系统访问文件,一定是要带上路径的。
当然,这样递归访问,效率是比较底下的,Linux中会将常访问的路径进行缓存,这样就能提高效率了