一、磁盘
磁盘可以存储大量的二进制数据,并且断电后也能保持数据不丢失。因此磁盘是一种永久性存储介质,在计算机中,磁盘是一个外设,也是唯一的机械设备。既然磁盘是一个外设,那么就意味着,磁盘和内存(掉电易失存储介质)相比就比较慢了。
目前所有的普通文件都是在磁盘中存储的。磁盘在冯诺依曼体系结构当中既可以充当输入设备,又可以充当输出设备。
1、磁盘的物理结构
磁盘的盘片/盘面是用来存储数据的,两面都有。磁头(每一面都有一个磁头)和盘面并没有接触。中间有音圈马达,一旦磁盘通电之后,盘片旋转,磁头摆动,马达可以控制磁头摆动,控制盘片旋转,通过磁头将二进制数据写到磁盘上。
因为磁盘上存储的是二进制数据,数据是两态的,而磁盘上有许多小的磁铁颗粒,所以磁头是通过改变磁盘上的正负性来写入数据的。
2、磁盘的存储结构
我们在知道了磁盘的物理结构后,知道盘片是用来存储数据的。那么磁盘是怎么通过磁头将数据存储到某一位置,然后又能重新找到呢?这就和磁盘的存储方法有关了。
如下图:
扇区:一块绿色的部分就是扇区。磁盘存储数据的基本单位。扇区大小512字节,512字节是硬件要求。
磁道:左图中,一圈一圈的灰色的同心圆就是磁道。磁盘上只有磁道位置能够存储数据,其他位置则不能存储数据。
柱面:多个半径相同的圆构成柱面。如右图紫色的部分。
如何将数据写到指定的扇区上:1、首先确认写到哪一个面上(用哪一个磁头去写入) 2、在哪一个磁道上 3、最后找到在哪一个扇区。
磁盘中存储数据,需要先定位扇区,定位任何一个扇区,采用的硬件级别定位方式(CHS定位法):柱面Cylinder——磁头Head——扇区Sector。
3、磁盘的抽象结构
由于操作系统并不认识磁盘的物理结构,因此操作系统在访问磁盘时必须使用自己的方式将磁盘的数据管理起来。我们可以把磁盘盘片想象成线性结构。在操作系统的角度,磁盘就是一个线性结构。我们使用数组来表示一个磁盘。要访问某个扇区,只需要找到数组下标,也就是说知道这个扇区的下标就算定位了一个扇区。
在操作系统中,我们称这种地址为LBA(Logic Block Address)地址。而要写到物理磁盘上,我们就要把LBA地址转换成对应磁盘的三维地址CHS地址。
于是在操作系统中,对于磁盘的管理,就变成了对于该数组的管理。操作系统能够通过某种方法,将LBA地址转换成CHS地址,进而可以访问磁盘数据。
二、文件系统与inode
1、初识inode
如下图:我们使用 ls -li 命令后,发现除了文件的名称、类型、权限、拥有者、所属组、大小最近修改时间这些内容,每个文件的最开始会有一串数字。那么这个数字是什么呢?其实这个数字就是该文件的inode编号。
那么inode编号代表着什么意思呢?我们接着往下看。
2、文件系统
在操作系统中,对于磁盘的管理,本质上就是对于磁盘抽象成的数组的管理。而我们知道,如果一个磁盘的空间是很大的,所以抽象出的数组也一定是很大的,那么操作系统如何管理这么大的数组的呢?
我们假设一个磁盘有500GB的大小。如果直接对这500GB进行管理,那是十分麻烦的。所以我们可以将磁盘分成多个小的分区。对一个小的分区进行管理。我们如果将所有小的分区管理好了,那么整个磁盘就管理好了。如果一个分区还是比较大,那么我们可以继续划分,最后,我们得到一个便于管理的块组。把一个块组管理好,这个分区就管理好了,分区管理好了,整个磁盘就管理好了。
下面我们对一个块组中的内容进行解释:
Boot Block:一个分区的最前面,有一个区域叫做boot block。它是启动块,存在每个分区的开头,备份文件与启动相关的。
Super Block:保存的是整个文件系统的属性信息。Super Block保存在各个块组里意味着备份,如果某个块组的 Super Block损坏,便可以通过拷贝其他块组的Super Block。
Data blocks:保存特定文件的内容。虽然磁盘存储数据的基本单位是扇区(512字节),但是操作系统(文件系统)和磁盘进行IO的基本单位是4KB。data blocks相当于多个4KB大小的空间的集合。Linux的文件=内容+属性,而Linux在磁盘上存储文件是将内容和属性是分开存储的。
inode table:inode是一个大小为128字节的空间,保存对应文件的属性。inode table 则是多个inode空间的集合,所以为了区别,每一个inode空间对应一个inode编号。即:一般而言,一个文件,一个inode空间,一个inode编号。
data blocks和inode tables都是由许多个小的空间组成的,那么我们在向磁盘写入数据时,我们怎么知道哪些空间被占用了,哪些空间没有被占用呢?我们可以使用block bitmap和inode bitmap来标注这些空间的占用情况。
block bitmap:data blocks对应的位图结构,位图中的比特位位置和当前data block对应的数据块位置是一一对应的。比特位为1,代表block被占用,否则表示可用。
inode bitmap:inode对应的位图结构,统计inode的使用情况,位图中比特位的位置和当前文件对应的inode的位置是一样对应的,比特位为1,代表inode被占用,否则表示可用。
GDT(group descripteor table):块组描述符,表示该块组的属性信息,如已经使用多少,inode有多少个,已经被占用了多少个,还剩下多少个。
格式化:当磁盘完成分区后,我们还需要对磁盘进行格式化。磁盘格式化就是对磁盘中的分区进行初始化的一种操作,即:磁盘格式化就是对分区后的各个区域写入对应的管理信息,如block bitmap和inode bitmap全部初始化成为0。所以格式化通常会导致现有的磁盘或分区中所有的文件被清除。
所以,一个块组的前四个部分被我们称为文件系统信息,后面两个部分就是文件的相关内容信息。
3、用inode编号找文件属性和内容
既然文件的属性和内容是分开存储的,那么我们要怎么通过inode编号去找到它呢?
首先,属性是很容易就可以找到的,因为我们只要知道了inode编号,就可以直接找到文件的属性。但是,想要找到文件的内容就不是那么容易了。第一点,我们无法通过某种方式直接找到,而且一个文件的大小是可以很大的,这就说明了一个文件的内容会被存储在多个 data blocks中,我们必须将所有的data blocks找到,才是找到了文件的内容,但是我们怎么知道哪些data blocks属于同一个文件。
那么我们应该怎么寻找文件的内容呢?在Data blocks中,每个data block都会有一个编号。而inode其实是一个结构体,它的里面除了文件的各种属性信息外,还有一个int blocks数组,该数组里保存的数字,就是对应的data block的编号,通过这个数组,我们就可以找到属于该文件的所有内容。
但是,这里就又有一个疑问了, blocks数组一般只能存15个编号,可是如果文件内容的data block个数多于数组大小呢?这当然是有解决办法的。
并不是所有的data block只能存放文件的内容,也可以存放其他块的编号,所以最终指向更多的data block来存储。如下图:
4、inode和文件名的关系
首先,我们要知道的是,在Linux中,inode属性里面并没有文件名的概念。但是,用户使用时使用的却是文件名,而不是系统认识的inode,这是为什么呢?
在一个目录下,可以保存很多的文件,且同一个目录下文件名是没有重复的。其实,目录也是一个文件,它也有自己的inode和data block。目录的data block中保存的就是该目录下的文件的文件名与其inode编号的映射关系。
5、创建一个文件
在inode bitmap中对应的比特位由0置为1,找到其inode table,把属性填进去,文件的数据写到block里,再inode和block建立映射关系,然后block bitmap中对应的比特位由0变为1,接着文件名和inode编号建立映射关系,最后返回inode编号,创建成功。
所以我们在一个目录下创建一个新的文件,必须有写的权限,新建一个文件的时候,要向当前目录的内容里去写文件名和inode的映射关系,所以必须得有写入权限。
6、查看一个文件
拿到inode找到inode table,在根据inode table找到对应的数据块,内容加属性就全找到了。
7、删除一个文件
实际上删除一个文件时,我们只需要找到inode在inode bitmap当中的比特位和block bitmap中的比特位,把比特位由1置为0,然后解除文件名和inode编号的映射关系。
所以把文件删除是能够恢复的,因为删除只是把比特位清掉了,想要恢复只要得到inode的编号,然后把inode bitmap里的比特位由0置为1,在去inode table对应的映射表,在block bitmap的0置为1。所以如果在Linux中误删除一个文件,还是能恢复的,但是前提必须是inode和data block没有被新的内容占用,所以当误删除一个文件时,最好的办法就是什么都不做。
三、软硬链接
1、软连接
我们先来看一看下面的问题:在 bin/exe 路径下有一个可执行程序 test,如果我们要在最开始的目录下执行它的话,我们要使用完整的路径。如果可执行程序在一个路径下藏得非常深,那么即使是使用相对路径,也比较麻烦。
所以,我们可以使用软连接来帮助我们快速找到可执行程序
ln -s myfile.txt soft_file.link
软连接就相当于Windows下的快捷方式:在我的电脑上,桌面上的微信指向的就是一个长路径下微信的可执行程序。
有自己独立的inode的称为软链接,即软链接是独立的文件,独立的文件有独立的inode和对应的文件内容。
2、硬链接
创建硬链接:
ln myfile.txt hard_file.link
软硬链接最重要的区别在于是否具有独立的inode,硬链接没有独立的inode,它的inode是与其链接文件的inode相同。
建立硬链接根本没有新增文件,因为没有给硬链接的文件分配独立的inode,所以创建硬链接本质就是在指定的路径下,新增文件名和inode编号的映射关系!相当于给文件取了一个别名。
我们再仔细观察,发现建立了硬链接后,数字变成了2,删除硬链接后,数字又重新变成了1。这个数字就叫做硬链接数。也就是这个文件有几个名字。
~ 为什么创建一个普通文件的时候,默认硬链接数是1?
因为一个普通文件在创建时用户是一定要取名的,因此文件本身就有一个自己文件名和自己的inode,具有一个映射关系。
~ 为什么创建一个空目录的时候,默认硬链接数是2?
首先目录和本身的inode就是一组映射关系了,第二,目录中还有一个目录 . 表示当前目录,该文件和inode也是一组映射关系,所以是硬链接数是2。
~ 现在在空目录dir下创建一个新的目录d1,此时dir的硬链接数就变成了3,为什么?
因为d1目录下有一个目录 .. 表示上级目录,也就是dir,所以硬链接数为3。