Linux - 文件系统 - 理解目录 - 理解 软/硬链接

前言

在上篇博客当中,我们对 文件系统 和 inode 做了初步了解,本博客将在上篇博客的基础之上,对于 文件系统当中的目录进行进步一阐述。

Linux - 进一步理解 文件系统 - inode - 机械硬盘-CSDN博客

目录

一个文件有一个 inode,每一个 inode 都是有自己的 inode 编号(这个inode 编号只在自己当前所在分区当中有效)

inode 的划分是以 分区为单位的,也就是说,各个分区当中的 inode 是独立的,inode 编号也是独立的。

虽然,inode 当中存储了 这个文件的所有属性,但是在这个++inode 当中不会存储 文件名++ 的。也就是说,++文件名压根就不属于 文件属性++

换言之,如果我们想要访问一个文件,如果这个文件名是在 inode 当中存储的,那么对于操作系统来说,用户就要告诉这个 操作系统 ,inode 是多少,才能拿到 文件名。

但是,如果是 小白用户,压根就不知道 inode 的存在,他知道 文件名,而且,我们日常在访问文件,修改文件,查找文件 的基本都是通过 文件名来操作的。

使用者从来没有关心过 inode 这个是什么,使用者对于操作文件都是通过 文件名来操作的。

而,文件名肯定是有重复的,操作系统如何识别这些重复的文件,其实靠的就是 目录,我们知道,有绝对路径 和 相对路径来找到某一个文件。

所以,其实我们是通过 目录来找到各个文件的。

那么目录是什么呢?


其实目录本质上也是一个文件:

++目录也是文件,目录也有自己独立的 inode++。也就是说,目录也有自己的 属性。

那么,在目录当中有内容吗

答案是++++ 的。那么目录 这个文件当中存储的是什么呢

++目录的数据块当++ 中,存储的是 目录当中的文件的 ++文件名++ 和 ++各个文件对应的 inode 的映射关系++ 。

所以,一个文件的文件名不是存储在 这个文件的属性(inode)当中的,文件的文件名不是这个文件的属性,这个文件的文件名 和 这个文件对应的 inode 的映射关系 是存储在当前文件所以在目录的内容当中的

所以,比如 ls 这个命令,在查找当前目录下的 文件和 目录的话,其实就是在当前目录的内容当中找到 本目录下的 文件名 和 各个文件映射的 inode 关系,根据命令行参数选项,打印出这个文件对应的信息即可。

所以,如果我们想要进入某一个目录当中,那么这个目录就要有 x 权限;当我们在某一个目录当中 创建一个新的文件,或者是 要删除某一个文件,需要这个目录有 w 权限

因为,就算我们在一个没有 w 权限的目录 执行路径 当中创建一个了一个新的文件,但是,这个文件的 文件名 和 这个文件对应的 inode 映射关系是不能再 保存在 这个 目录文件对应的数据块当中。

同样,如果是这个目录是没有 r (读)权限的,那么这个目录当中的文件是不能访问的,因为 要像访问一个文件,或者是修改一个文件,那么就要拿到这个文件的 inode 。但是,因为目录文件是不给读的,所以拿不到想访问文件的inode,那拿不到 inode 怎么访问文件呢?


而像是 绝对路径和相对路径,也是同一个 根目录 或者是 当前目录 文件的数据块当中,一层一层递归的方式来寻找的。

所以,如果我们要想访问 当前目录当中的某一个目录的话,就需要找到这个目录的 inode,才能访问到这个目录文件。

但是,要先找到这个 目录的 inode ,就要在这个目录的上一层的 目录文件的数据块当中找到这个目录文件的 inode映射关系。

到这你可能就会想,那么这不就递归了吗?我们要想找到这个目录的 inode 就要一直往上去递归式的去寻找。

是的,是递归式的寻找,但是,不是无穷无尽的递归,因为 我们从任何路径当中 往上来递归式寻找的话,一定可以找到一个目录 --- 根目录。

所以的目录都是从 根目录 衍生出来的。

所以,绝对路径就是 先递归式的返回遍历到 根目录,再根据 给出的绝对路径 来找到 对应文件

相对路径就更简单了,只要是当前目录路径已经被找到了,只需要按照相对路径当中给出的路径来进行查找即可。

得出结论:

  • 在Linux 当中,访问任何一个 路径都需要带上路径,可能你在使用 ls 等等这些命令的时候,没有带上路径,但是同样也访问到了 目录文件,或者是文件当中的内容。其实这些命令访问文件也是要 路径的,只不过,我们可以通过设置一些环境变量来 提前保存一些路径,这些我们称之为 -- 默认路径,系统就会默认从 这个路径当中来访问文件,但是其实本质上也是 通过路径来访问到内容的。

而,像上述要像递归到根目录的方式,来查找 文件,这种方式太慢了,所以,在 Linux 当中,会把我们曾经访问过的,或者是经常访问的 若干目录, 已经这些目录当中的若干信息(比如 文件映射的 inode,文件名等等信息),缓存一份。---- ++dentry缓存++。

当我们需要访问 缓存当中存在的文件之时,就可以直接从 缓存当中读取到 这个文件的 inode 等等信息,直接访问到这个文件了,不需要再去递归式的寻找 文件位置。

软链接 和 硬链接

我们先来看是如何创建一个 文件的 软链接硬链接的:

软链接;

上述就是创建一个 软链接,此时就有一个 text_link 指向 text.c 文件了。

如果你查看这个 text_link 的属性,你会查看到 这个 text_link 有 inode ,说明这个 text_link是一个文件,而且,在这个文件的后面还有一个 数字,你可以看到是1:

你可以发现这个 text_link是有 inode的 ,说明这个 text_link是一个 文件,而且,在 这个 text_link 和 text.c 两个文件的访问权限 后面 还有一个 数字1 ,这个数字1 我们在后面 说到 硬链接的时候再叙述

所以,此时也就是相当于是 有一个 text_link 软链接文件指向了 text.c 这个文件。


硬链接:

像上述就生成一个 硬链接文件。

同时,这个 新生成的 text_link 硬链接文件,也是有 inode 的,但是这个 ++inode 是和 text.c 文件是一样的++ ,说明这个 硬链接不是一个独立的文件,而且,此时,在 text_link 这个文件的 访问权限符 后面的 数字,变成了2

而且,相信你还注意到 ,我们对应生成目标文件的 硬链接文件的目标文件,也就是 text.c 这个文件。在文件访问权限符之后的数字,在生成 硬链接文件之前,本来是 1 的,但是在生成 硬链接文件之后就变成了2。


对于上述的结果,我们先不做阐述,我们下来看看 生成 软链接文件 和 硬链接文件之间的语法是什么:

其实,都是使用 ln 这个语法,但是吗,如果是软链接文件,需要带上 -s 这个选项参数,其实这里的 -s 就是 Soft 软的这个单词的缩写。

如不带上 -s 这个选项那么,默认就是 硬链接文件的生成方式。、

创建软链接和硬链接的语法:

bash 复制代码
ln -s 被指向文件名 生成的目标指向文件的软链接文件名
ln 被指向文件名 生成的目标指向文件的软链接文件名



ln -s text.c text_link   #生成一个text_link 软链接文件指向 text.c 文件
ln  text.c textlink   #生成一个text-link 硬链接文件指向 text.c 文件

我们先来说说,上述所说的 在文件访问权限符之后的 数字代表的是什么意义

其实这个数代表的意义是代表这个文件当前的++硬链接个数++ 。(其实就是 当前 inode 的使用文件的++引用计数++)

其实,此时,如果我们把++++ 一个文件的 ++软链接文件++ 和++硬链接文件++ ,都创建出来:

你会发现,++硬链接文件(上图的text-link文件) 和 链接的文件(上图的text.c文件) 的 inode 是一样的。++

但是,++软连接文件的 inode 和 其他两个文件的 inode 是不一样的++。

硬链接不是一样的独立的文件,因为硬链接文件 没有独立的 inode。


理解硬链接

因为硬链接文件的 inode 和 链接的文件的inode是一样的 。所以,这两个文件的属性应该是一样的

这里也侧面的证明了 ,文件的文件名是不在 文件的inode 当中存储的,而是在目录当中存储的。

而,++所谓的建立硬链接,本质上其实就是在特定的 目录的数据块当中,新增 文件名 和 文件和inode 的映射关系。++

简答来说,就是在 目标文件所在目录的内容当中(也就是在目录的数据块当中),把 新按照目标文件生成的 硬链接文件的 文件名和 对应的 inode 映射关系,保存到 目标文件所在目录的内容当中。

如果此时,我们在硬链接文件存在的情况下,删除 这个硬链接文件链接的 目标文件的话,会出现什么结果呢?

上述是结果,下述是删除 text.c 文件之前的结果:

发现,就算我们删除了text.c 这个文件,但是,硬链接文件并没有失效,inode 还是和之前一样,跟删除的 目标文件的 inode 保持一致,并没有发生改变

但是,引用计数 变成了1,因为此时 硬链接个数又变成了1个。

像上述这种,先创建一个文件的 硬链接文件,然后删除掉这个文件,保存这个文件的硬链接文件,这个操作被称之为 -- ++取别名++。


所以,在每一个 inode 内部 ,都有一个 作用于 当前 ++inode 硬链接个数++ 的 ++引用计数++

而,在++目录当中,保存了 每一个 文件名 对应 映射的 inode 的信息++。

可以存在 不同的文件名,映射到同一个 inode 当中。

所以,现在我们可以有一个更好的对于 ++引用计数的概念++ ,不在是 硬链接文件个数了,而是 ++有多少个 文件名 映射该 inode++。

理解软链接

软链接文件当中,你可以发现,其实软链接文件是一个新创建的独立的文件。因为在创建之后,有独立的 inode。所以,软链接不会影响 链接的目标文件的 引用计数。

那么既然有 独立的 inode ,也就意味着有独立的 数据块,也就是说有独立的存储空间,在这个文件当中要存储什么呢?

++存储的是 指向的目标文件的路径。++

其实你可以理解为 在软链接当中存储的是 ,指向目标文件的 ++指针++ ,通过这个指针可以访问到 这个软链接指向的目标文件

发现,在text.c 当中重定向的字符串 aaaaa ,通过 text-link 这个软链接文件也可以访问到。

所以,既然存储的是指针,那么就会有 ++野指针的情况,当我们把软链接指向的 目标文件 删除之时,那么这个 软链接文件当中存储的指针就会失效、++

如上所说,从蓝色的软连接文件名,变成了红色的,此时代表的意思就是已经出现连接错误了

其实,这个软链接 特别像windows 当中 程序的快捷方式

当我们查看这些 程序的快捷方式的属性的话,可以看见一个 目标的属性:

其实这个就是我们上述所说的,软链接当中存储的是 指向目标文件的 路径。 其实是一样的 。


为什么要有 软硬链接

我们日常使用的程序软件,其实都不简简单单是一个 xx.exe 这种直接点击就能运行的程序。整个程序一般还是有自己的 配置文件,或者是程序运行所需要的文件数据信息,所以,往往一个程序的 xx.exe 是藏在一个较深的路径当中:

而,如果我们想在当前目录下(不在这个程序的 xx.exe 文件下)直接运行这个程序的话,就必须要带上绝对路径或者是 相对路径。

但是类似 D:/ProgramFiles(x86)/Huorong/Sysdiag/bin/xxx.exe 这行来运行这个可执行程序就太麻烦了,所以,可以使用 软连接的方式 创建快捷方式,来调用这个可执行程序

同样,按照上述的方式,我们可以在Linux PATH 环境变量当中创建出我们自己,或者是第三方的 程序的 软链接文件,这样就可以直接 输入 文件名,不用的现去在当前目录下创建 对应的 软链接文件,都可以直接 调用 我们想安装的 程序的可执行文件了

此时我们就可以直接,在任何路径下调用这个 我们刚刚安装的 程序了:

所以,这个软件安装到哪里都可以,只要在 PATH 环境变量 指向的 系统默认的 路径目录当中创建了 这个程序的 软链接程序,就可以随时随地调用这个程序了。


其次,当你创建了一个新的目录,那么你会发现,这个目录的 ++硬链接个数++ 是 2 个。其实你应该已经猜到为什么了:

在上图当中,就有一组 inode 和 文件名 的关系,就是当前的dir 这个目录文件名 和 这个文件的inode 的映射关系。现在我们进入到这个目录当中,查看这个目录当中所有文件,包括隐藏文件:

有一个 "." 作为文件名的 文件,很多读者应该知道,这个 "." 文件,代表的是当前所在 所在目录的这个目录的文件。

也就是说,在 dir 这个目录当中的 "." 这个文件,和 dir 这个目录文件 所映射的 inode 是一样的,两个映射的是同一个 inode,代表的是同一个文件。

而且如上图所示,你可以发现 dir 和 dir当中的 "." 这两个文件名的 inode 是相同的。

所以,这里你就可以理解了 ,为了 每一个目录当中的 "." 文件,都可以代表的是 当前目录文件。

上述也提到了 ".." 两个点的文件名,这个文件代表的是当前目录的 上级目录文件,和上级目录文件共用的是同一个inode。

所以,按照这个推理的话,在上述创建 dir 这个目录 所在目录,应该就有 3 个 硬链接个数了,因为在 dir 当中还有一个 ".." 文件是映射的 这个目录:

如上图所示,ln_text 目录就是 dir 所在的目录,是三个 硬链接个数。

同样你可以查看 ++"/" 根目录++ 的 硬链接个数:

发现是一个很大数字,因为在 "/" 目录当中已经创建了很多个 目录了,每一个目录当中都有一个 ".." 硬链接上 "/" ,所以才会有这么多。

所以,往后,如果想知道某一个 目录当中有多少个 有效目录(也就是想上述 dir 这样目录)其实可以像上诉一样查看这个目录的 硬链接个数,该目录的 ++硬链接个数 - 2++ 就是这个 目录当中的有效目录。
Linux 当中的目录结构是一个多叉树,Linux 当中的文件系统是利用 上述的 硬链接方式,来 维持多叉树当中每一个 结点当中的有 parent指针 和 指向当中结点的指针,这样一个关系。我们称之为 -- ++路径定位++。实现目录间的切换。

然后使用在目录当中存储的 文件名 和 文件名所映射的 inode 来位置当前结点的孩子结点直接的关系。


在上述你可能有疑问,为什么可以直接用一个目录的 硬链接个数来确定其中的 有效目录个数?

就不怕 用户自己使用 ln 这个指令来对 这个目录文件进行 硬链接吗?

其实++不怕++ 。因为 ++目录是不能使用 ln 创建硬链接的++。

如上所示,我们发现报错了,报错信息是 链接不允许是 目录。

但是,++目录是可以建立 软链接的++。

这里需要注意是:如果你想删除某一个 软链接的话,可以使用 rm 命令,但是有的时候是删不掉的,这个时候更多的使用的事 ++unlink 软链接文件名++ 这样的方式来进行删除软链接文件的。


为什么Linux 不给 目录建立硬链接?

我们可以假设一下,然后来考虑为什么。其实很简单,就是一个++循环引用计数++的问题。

如上图所示,dir 目录文件是 ln_text 目录文件的硬链接,dir 就相当于是我们在某一个目录下 创建的一个ln_text 目录文件的 硬链接文件。

那么在上述 多叉树文件系统当中,如果我想从 ln_text 找到 dir 这个目录的话,从上图当中的红色路径就可以找到,但是,当我们找到 dir 之后,它的 inode 又是 2(和 ln_text 是一样的),所以此时就会回去找到 ln_text 目录, 又回到 最初的起点,但是还是没有找到,所以又会像之前一样往下递归找到 dir 目录·······

这不就是一个循环了吗?

而,上述说过 "." 和 ".." 两个文件不也是建立了 硬链接吗

这两个文件不是用户建立的,是操作系统自己建立的,它在建立之初,因为 这两个文件和自己硬链接的文件 不会像上个例子一样 隔个十万八千里,人家就是表示的当前目录和 上级目录,所以这个在操作系统内部可以实现。但是如果放在很长的 文件系统多叉树结构当中就不好实现了。

换句话说,操作系统自己能够 实现目录的硬链接,本质上其实是 操作系统只相信自己,不相信任何人,包括 root 。

同样你也可以发现,关于 "." 和 ".." 这两个文件是不能做 搜索操作的吗,只能在 路径定位当中使用。

换言之,操作系统之所以要 才上 循环引用的坑也要 弄出 "." 和 ".." 这两个文件,就是为了引出 相对路径这个概念,让我们更好的使用 文件系统。

相关推荐
广而不精zhu小白5 分钟前
CentOS Stream 9 挂载Windows共享FTP文件夹
linux·windows·centos
一休哥助手10 分钟前
全面解析 Linux 系统监控与性能优化
linux·运维·性能优化
二进制杯莫停12 分钟前
掌控网络流量的利器:tcconfig
linux
LI JS@你猜啊23 分钟前
Elasticsearch 集群
大数据·服务器·elasticsearch
watl029 分钟前
【Android】unzip aar删除冲突classes再zip
android·linux·运维
团儿.1 小时前
Docker服务发现新纪元:探索Consul的无限魅力
运维·docker·云计算·服务发现·consul
赵大仁1 小时前
在 CentOS 7 上安装 Node.js 20 并升级 GCC、make 和 glibc
linux·运维·服务器·ide·ubuntu·centos·计算机基础
vvw&1 小时前
Docker Build 命令详解:在 Ubuntu 上构建 Docker 镜像教程
linux·运维·服务器·ubuntu·docker·容器·开源
李白你好1 小时前
家用无线路由器的 2.4GHz 和 5GHz
运维·网络
苹果醋31 小时前
React系列(八)——React进阶知识点拓展
运维·vue.js·spring boot·nginx·课程设计