之前的文章中我们与文件有关的内容谈论的都是被打开的文件,那么如果文件没有被打开呢?这样文件就一定不再内存中,只能在磁盘外设中存储,本文中我们就来讲述磁盘中文件的相关知识。
磁盘的物理存储结构
一个磁盘由多个盘片叠加而成,每个盘片有两面,盘片的表面有着磁性物质,这些磁性物资通过会被用来记录二进制数据。
磁盘中存储的基本单元:扇区一般是512字节或者是4kb,一般磁盘都有的扇区都是512字节。在同半径下的所有扇区被称为磁道。
在一面上,如何在硬件上定位一个扇区?1、可以先定位在哪一个磁道 - 由半径决定;2、再确定在该磁道的那一个扇区 - 根据扇区的编号,定位一个扇区;同时因为每一个面上都有着磁头,磁头就可以表示此时处在那一个面上。至此我们想要定位任意一个扇区就有了方法,通过磁头(head)确定在哪一面,通过柱面(磁道cylinder)确定在哪一个磁道,通过扇区(sector)找到想要的扇区。这种方法被称为CHS法。既然我们能够使用CHS法定位任意一个扇区,我们就能定位任意多个扇区,从而将文件从硬件角度,进行读取或者写入。
物理到逻辑的抽象
OS如果得知了任意一个CHS地址就能访问任意一个扇区,但是在OS中并不是直接访问的CHS地址,为了避免当硬件发生变化,操作系统也要变化,OS要和硬件解耦。扇区对于IO来说512直接太小了,OS实际进行IO,基本单位是4KB(可以进行调整)磁盘 -- 块设备,OS需要一套新的地址,进行块级别的访问。
我们可将磁盘按照磁道拉成一个线性结构,一个盘面就是一个线性结构,与靠近外圈的就是结构前面的内容,越靠近内部的就是结构后面的内容,同时在这个线性结构中同一个磁道的数据一定是紧挨着的。
我们可以将其看做一个数组,初步完成了一个从物理地址到线性逻辑地址的抽象过程,数组天然有着下标,此时定位一个扇区,只需要一个数组下标。而其中OS是以4KB为单位进行IO,一个OS级别的文件块要包括8个扇区。
计算机常规的访问方式:起始地址 + 偏移量的方式(在语言级别上是数据类型)。当操作系统访问数据块的时候,只需要知道数据块的起始地址(第一个扇区的下标地址)+ 4KB(块的类型)我们将数据块也看做一种类型。
所以块的地址本质就是数组的一个下标N,以后我们表示一个块就可以采用线性下标的方式,定位任意一个块。这种定位的方式在操作系统内叫做LBA -- 逻辑块地址。
但是,我们的磁盘只认识CHS,如何将LBA与CHS互相转化?
OS要管理磁盘,就将磁盘看做一个大数组,对磁盘的管理就变成了对数组的管理,通过先描述再组织的形式进行管理,struct block{}。
下面来介绍一下OS如何对这个数组进行管理呢?
文件系统
由于空间还是非常的大,我们就可以将大空间分为小空间,通过在小空间的管理,重复操作至大空间上,每一个小块依旧很大因此OS还需要对分区的空间进行分组。
Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。
文件 = 内容 + 属性,而在Linux中是将内容和属性分离的。无论是内容还是属性都要以块的形式保存在磁盘的某个位置。
- Super Block:存放文件系统的所有属性信息1、文件系统的类型;2、整个分组的情况。SB在各个分组里面可能都会存在,而且是统一更新的,为了防止SB中的区域出现损坏,如果SB出现了故障整个分区就不可以被使用,因此要做好备份。
- Group Descriptor Table:组描述符 -- GDT 该组内的详细等属性信息
- inode Table:一般而言一个文件,内部所有的属性的集合 -- inode(128字节),一个文件,一个inode。一个分区会存在大量的inode节点,一个group需要有一个区域专门来保存该group内的所有文件的节点 -- inode Table。分组内部会存在多个inode,每一个inode都会有自己的inode编号,inode编号也属于对应文件的属性id。
- Data Blocks:对于固定大小的文件属性而言,文件的内容是变化的,我们是用数据块来进行文件内容的保存的,所以一个文件要保存内容就需要[1, n]个数据块。Linux查找一个文件,是要根据inode编号,来进行文件的查找,包括读取文件,一个inode对应一个文件,而改变文件属性和该文件对应的数据块,是有映射关系的。
- inode Bitmap:每个bit表示一个inode是否空闲可用。
- Block Bitmap:Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没
有被占用
1、Linux系统只认inode号,文件的inode属性中并不存在文件名。文件名是给用户使用的。
2、目录也是文件,有inode也有内容。
3、任何一个文件,一定存在一个目录内部,目录的数据块中保存的是该目录下文件名和文件inode编号对应的映射关系,而且在目录内文件名和inode互为key值。
4、当我们访问一个文件的时候,是在特定的目录下访问的,例如 cat log.txt 指令:先要在当前目录下,找到log.txt的inode编号;一个目录也是一个文件,以一定隶属于一个分区,在该分组中找到分区,在该分区的inode table中找到inode;通过inode和对应的data table的映射关系,找到该文件的数据块,并加载到OS,完成显示到显示器。
一些区域的细节:
根据文件名找到inode number;根据inode number -> inode属性中的映射关系,设置block bitmap对应的比特位为0;根据inode number设置inode bitmap对应的比特位为0;
inode确定分组,inode number是在一个分区内唯一有效,不能跨分区。分区、分组、填写系统属性都是OS做的,分区完成之后,要让分区能够正常的使用需要对分区做格式化,格式化的过程就是OS向分区写入文件系统的管理属性信息。
inode如果仅仅用数组与datablock建立映射关系,那一个文件不是只有很小的容量,这显然是不可能的。OS在inode的结构中的datablock数组前面的一部分存放一些比较小的文件使用直接索引的方式,后面还会有二级索引、三级索引,通过在datablock的数据块中存放其余数据块的内容,达到可以存放一些较大的文件。
软硬链接
软链接
软连接是一个独立的文件,有自己的inode number 必有自己的inode属性和内容。软链接内部放的是自己所指向的文件的路径。
硬链接
硬链接和目标文件共用的是一个inode number,没有独立的inode,意味着硬链接一定是和目标文件使用同一个inode。硬链接只更改了目录的内容,建立了新的文件名和老的inode的关系。
当我们把源文件删除时候会发现出现了链接错误的问题:
软链接的目的
将一个路径很深的程序或库或头文件建立到当前目录下: