👉前言👈
之前我们所谈论的文件都是被打开的文件,但是磁盘上还有非常多没有被打开的文件,操作系统是如何管理这些文件的呢?这一部分就是文件系统的内容了,为了更好了解文件系统,我们先来认识一下磁盘。
👉磁盘👈
磁盘的物理结构
磁盘是计算机中唯一的一个机械结构,又因为磁盘是外设,所以磁盘访问会很慢!(CPU 是纳秒级别,内存是微秒级别,磁盘是毫秒级别的)我们目前是很少见到磁盘了,但是在企业里,磁盘存储依旧是主流。
注:一片盘片有两面,两面都能够读写数据,每一面都有一个磁头,磁头是悬浮在盘片上。磁盘的盘面是充满磁的,其上面存在着许多非常细小的 N、S级,磁盘是通过 N、S级来表示 0 和 1。通过充磁和消磁技术,来调转 N、S 级,从而达到 0 和 1 的写入,那么就可以表示数据了。
磁盘的存储结构
磁盘的逻辑结构
👉文件系统👈
Linux ext2 文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同)。磁盘是典型的块设备,硬盘分区被划分为一个个的 block,一个block的大小是由格式化的时候确定的,并且不可以更改。例如:mke2fs 的 -b 选项可以设定 block 大小为1024、2048或4096字节,而上图中启动块(Boot Block)的大小是确定的。
Block Group:ext2 文件系统会根据分区的大小划分为数个 Block Group,而每个 Block Group 都有着相同的结构组成。
超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode 的总量、 未使用的 block 和 inode 的数量、一个 block 和 inode 的大小、最近一次挂载的时间、最近一次写入数据的时间和最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block 的信息被破坏,可以说整个文件系统结构就被破坏了。
Group Descriptor Table(GDT):块组描述符,描述块组属性信息。
块位图(Block Bitmap):Block Bitmap 中记录着 Data Block 中哪个数据块已经被占用,哪个数据块没 有被占用。
inode 位图(inode Bitmap):每个比特位表示一个 inode 是否空闲可用。
i 节点表:存放文件属性 如文件大小、所有者和最近修改时间等。
数据区:存放文件内容。
inode 和 data block
我们知道:文件等于文件内容加文件属性,而文件内容和文件属性是分开存储的。文件属性是保存在 inode 中的, inode 是固定大小的(通常是128字节,视具体文件系统而定)。一般情况下,有一个文件就会有一个 inode。文件几乎所有属性都储存在 inode 中,文件名并不在 inode 中存储!文件内容存储在 data block 中,其大小随着应用类型的变化而变化。
inode 为了进行区分彼此,每个 inode 都会有自己的 ID 编号。
inode Table 中保存了分组内部所有可用的 inode,可用的 inode 是包括已经使用的和未被使用的。 Data blocks 中保存的是分组内部所有文件的数据块,以4KB为基本单位。创建文件时,先在 inode Table 中找到没有被使用的 inode 将文件的属性写进去;内容也是找到没有被使用的数据块,然后再将数据写入数据块中。查找 inode 位图和数据块位图就可以知道哪些 inode 和数据块没有被使用。位图结构用比特位来代表有没有被使用,1 代表被使用,0 代表没有被使用。inode 位图比特位的位置和当前文件对应的 inode 的位置是一一对应的,数据块位图中的比特位和文件对应的数据块位置也是一一对应的。
块组描述表(Group Descriptor Table)保存的是对应分组的宏观的属性信息,如:该块组有多少 inode 和数据块,inode 被用了多少等等。
同一个分区的 inode 编号是不会重复的,是统一编号的。查找一个文件的时候,统一使用的是 inode 编号。有了文件的 inode 编号,先确定其在哪一个分组,再去 inode Bitmap 中查找对应的比特位是不是 1。是 1 则有效,再去 inode Table 中查找指定的 inode 编号,就可以找到文件的属性信息了。inode 本质是一个结构体,其中包含了一个数据块数组。该数据块数组中存储的就是文件的数据块编号。
如果想要查看一个文件,就可以通过 inode 编号找到该文件的数据块数组 blocks[15],进而找到该文件的数据块,组合成整个文件。从 blocks[12] 开始,其指向的是一个数据块。该数据块中保存的是其他的数据块编号,这些块也可以存储别的数据块编号,进而 blocks[15] 表示的就不止 15 个数据块了,可以是很多个。也就是说一个文件的数据块可以很多,文件的大小可以很大。
删除文件只需要找到 inode 在 inode Bitmap 中的比特位和 Block Bitmap 的比特位,将这两个比特位改成 0,文件就算删除了。恢复文件则与该过程相反,知道删除文件的 inode,再将 inode Bitmap 和 block Bitmap 中对应的比特位改成 1 即可恢复文件。删除文件的 inode 可以通过日志来查到。误删文件后,千万不要新建文件。以防误删文件的 inode 编号和数据块被占用,无法恢复误删文件!
而我们查看文件使用的是文件名,并没有使用 inode 来查看文件。其实文件名和 inode 存在一一映射的关系,目录的数据块放的就是当前目录文件名和 inode 的映射关系。所以同一个目录下,不可以存在同名的文件。因为文件名就是一个 key 值,通过该 key 值找到对应的 inode 编号,进而找到该文件!!!所以在一个目录里创建文件,必须要有该目录的写入权限。因为要将文件名和 inode 的映射关系写入到目录的数据块中。
软硬链接
我们知道,真正找到磁盘上文件的并不是文件名,而是inode。 其实在 Linux 中可以让多个文件名对应于同一个 inode。硬链接是通过 inode 引用另外一个文件,软链接是通过名字引用另外一个文件。
ln -s 现有文件 目标文件 #将目标文件与现有文件进行软链接 ln 现有文件 目标文件 #将目标文件与现有文件进行硬链接 unlink 文件名 #删除软链接文件
指令ll -i从左到右依次罗列的信息是:inode 编号、文件类型和文件权限、引用计数、文件拥有者、所属组、文件大小(单位是字节)、最后修改时间、文件名。
软链接和硬链接的区别是是否有独立的 inode!软链接生成的文件具有独立的 inode,可以被当做独立文件来看待。而硬链接形成的文件并没有独立的 inode,其 inode 是原来文件的 inode。也就是说,建立硬链接并没有创建新文件。因为没有给硬链接生成的文件分配独立的 inode。既然没人创建新文件,那么其一定没有自己的属性集合和内容集合,用的一定是别的文件的 inode 和内容。硬链接的本质是让 inode 中的引用计数count++,因此引用计数也被称作硬链接数。
当一个文件的引用计数(硬链接数)变成 0 时,该文件才算真正被删除。注:同一个 inode 的文件就算是同一个文件。
硬链接就是相当于给原有文件取别名,硬链接生成的文件和原有文件对应的 inode 是相同的。原有文件删除,并不会影响硬链接生成的文件,只是 inode 中的引用计数减去了 1。但软链接却不同,软链接并不是使用 inode 编号来表示的,而是通过文件名来标识的。软链接生成的文件有独立的 inode,也就有自己的数据块,其数据块中保存了原有文件的路径。如果删除了原有文件,那么软链接就失效了。但是如果在新建相同名字的文件,软链接会再次生效。但文件的内容肯定是不一样的,这相当于偷梁换柱。
软链接的优势:软链接就相当于 Windows 系统下的快捷方式,它能够帮助我们快速地找到指定路径的文件。
理解创建普通文件和目录文件的默认硬链接数
为什么创建一个普通文件的默认硬链接数是 1 呢?因为一个普通文件,自身就和该普通文件的 inode 建立一个映射关系,所以创建一个普通文件的默认硬链接数就是 1 了。
那为什么创建一个目录文件的默认链接数是 2 呢?其实是当前路径 lesson21 的目录文件 empty 的 inode 编号为790346,目录文件 empty 中的当前目录.的 inode 编号也是790346。所以,创建一个目录文件的默认链接数就是 2 了。如果在 empty 中再创建一个目录 Test,那么790346的引用计数(硬链接数)又会增加一。因为 Test 中的上级目录.. 的 inode 编号也是790346。
Linux 是不允许普通用户给目录建立硬链接的。原因是引入了对目录的硬连接就有可能在目录中引入循环,在目录遍历的时候系统就会陷入无限循环当中,这样导致无法定位到访问目录。Linux 的目录结构是一棵以 “/” 为根节点的树,如果允许自定义硬连接,则很有可能会破坏这个结构,甚至形成循环;而一旦形成循环,对于需要遍历目录树的命令,是致命的。所以为了避免对目录树结构的破坏,Linux 不允许用户自定义硬连接在目录上。
但是可以为目录建立软链接,因为软链接生成的文件会有独立的 inode 且该文件的类型为l。注:. 和 .. 是操作系统给目录建立的硬链接。
ACM 时间
A(Access):最后一次访问文件的时间。这个时间并不是访问一次就会更新,而是达到一定的访问次数或者最近两次访问时间的间隔比较长才会更新该时间。因为访问文件的概率比修改文件的概率要大得多,所以如果该时间被频繁更改会降低 Linux 系统的效率。
C(Change):最后一次修改文件属性的时间。一般文件内容被修改,文件属性的修改时间也会更新,因为文件的大小也会方式变化。
M(Modify):最后一次修改文件内容的时间。
touch指令可以将以上三个时间全部更新为当前时间。
细节:所有文件的属性和位图结构需要先被加载到内存中,才能进行更改数据的更改。更改完后,才能将数据写回到磁盘中。
👉总结👈
本篇博客主要讲解了磁盘的物理结构、存储结构和逻辑结构、文件系统中的 inode、data block、位图结构、软硬链接已经文件的 ACM 时间等。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️