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 这个选项那么,默认就是 硬链接文件的生成方式。、

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

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 。

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/165691.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis打包事务,分批提交

一、需求背景 接手一个老项目,在项目启动的时候,需要将xxx省整个省的所有区域数据数据、以及系统字典配置逐条保存在Redis缓存里面,这样查询的时候会更快; 区域数据字典数据一共大概20000多条,,前同事直接使用 list.forEach…

Windows安装MongoDB

1、下载MongoDB的zip,解压 2、创建目录 mkdir D:\JavaSoftware\Database\MongoDB\mongodb-win32-x86_64-windows-5.0.8\data\db mkdir D:\JavaSoftware\Database\MongoDB\mongodb-win32-x86_64-windows-5.0.8\data\log 3、创建一个配置文件mongod.cfg&#xff0c…

【PPspliT】ppt转pdf-保留过渡动画

网址 http://www.maxonthenet.altervista.org/ppsplit.php 下载安装 使用 再次打开ppt,就能在上方的选项栏里头看到了:

RabbitMQ基础教程

1.什么是消息队列 消息队列(Message Queue),我们一般简称为MQ。消息队列中间件是分布式系统中重要的组件,具有异步性、松耦合、分布式、可靠性等特点。用于实现高性能、高可用、可伸缩和最终一致性架构。是大型分布式系统不可缺少…

BUUCTF [WUSTCTF2020]find_me 1

BUUCTF:https://buuoj.cn/challenges 题目描述: 得到的 flag 请包上 flag{} 提交。 感谢 Iven Huang 师傅供题。 比赛平台:https://ctfgame.w-ais.cn/ 密文: 下载附件,得到一个.jpg图片。 解题思路: 1、得到一张图…

Matlab三角剖分插值问题分析

目录 前言 一、问题引入 二、一个例子 1.生成散点图 2.对数据进行剖分 3.点法式分析 三、最后结果 前言 上一篇文章感觉对三角剖分问题没有说清楚,这次专门对三角剖分问题再仔细说说。 一、问题引入 实际上这个问题是用来解决二维曲面插值问题的。 二维插值问题&…

外部中断为什么会误触发?

今天在写外部中断的程序的时候,发现中断特别容易受到干扰,我把手放在对应的中断引脚上,中断就一直触发,没有停过。经过一天的学习,找到了几个解决方法,所以写了这篇笔记。如果你的中断也时不时会误触发&…

通过Spring整合MyBatis实现持久层操作

文章目录 为什么要整合Spring和MyBatis?步骤一:添加依赖步骤二:配置数据源步骤三:配置MyBatis步骤四:创建Mapper接口和XML文件步骤五:使用Mapper接口拓展:事务管理 🎉通过Spring整合…

Leetcode173. 二叉搜索树迭代器

Every day a Leetcode 题目来源:173. 二叉搜索树迭代器 解法1:中序遍历 我们可以直接对二叉搜索树做一次完全的递归遍历,获取中序遍历的全部结果并保存在数组中。随后,我们利用得到的数组本身来实现迭代器。 代码&#xff1a…

竞赛 : 题目:基于深度学习的水果识别 设计 开题 技术

1 前言 Hi,大家好,这里是丹成学长,今天做一个 基于深度学习的水果识别demo 这是一个较为新颖的竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/pos…

Spark-06:共享变量

目录 1.广播变量(broadcast variables) 2.累加器(accumulators) 在分布式计算中,当在集群的多个节点上并行运行函数时,默认情况下,每个任务都会获得函数中使用到的变量的一个副本。如果变量很…

开启数据库审计(db,extended级别或os级别),并将审计文件存放到/home/oracle/audit下

文章目录 开启数据库审计(db,extended级别或os级别),并将审计文件存放到/home/oracle/audit下一. 简介二. 配置2.1. 审计是否安装2.2. 审计表空间迁移2.3. 审计参数2.4. 审计级别2.5. 其他审计选项2.6. 审计相关视图 三. 使用3.1. 开启/关闭审…

成为独立开发者有多难

首先自我介绍:我是一名前端开发工程师,7年的前端开发经验。CSDN 九段刀客_js,vue,ReactNative-CSDN博客,80多万的访问量,1万多的粉丝。 相信80%的程序员的终极梦想都是成为一名独立开发者,不用找工作有自己的产品可以有睡后收入。…

深度学习模型训练计算量的估算

深度学习模型训练计算量的估算 方法1:基于网络架构和批处理数量计算算术运算次数前向传递计算和常见层的参数数量全连接层(Fully connected layer)参数浮点数计算量 CNN参数浮点数计算量 转置CNN参数浮点数计算量 RNN参数浮点数计算量 GRU参数…

刷题学习记录(含2023ISCTFweb题的部分知识点)

[SWPUCTF 2021 新生赛]sql 进入环境 查看源码,发现是get传参且参数为wllm fuzz测试,发现空格,,and被过滤了 同样的也可以用python脚本进行fuzz测试 import requests fuzz{length ,,handler,like,select,sleep,database,delete,h…

java学习part09类的构造器

1. 2.默认构造器 如果没有显式定义任何构造器,系统会默认加一个默认构造器。 如果定义了,则不会有默认构造器。 默认构造器的权限和类的权限一样,类是public构造器就是public,类是缺省默认构造器就是缺省 反编译之后添加的构造…

解决DaemonSet没法调度到master节点的问题

最近在kubernetes部署一个springcloud微服务项目,到了最后一步部署边缘路由:使用nginx-ingress和traefik都可以,必须使用DaemonSet部署,但是发现三个节点,却总共只有两个pod。 换句话说, DaemonSet没法调度…

UML建模图文详解教程05——包图

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl本文参考资料:《UML面向对象分析、建模与设计(第2版)》吕云翔,赵天宇 著 包图概述 包图(package diagram)是用来描述模型中的…

一个最简单的工业通讯数据分析例子

1.背景 对工业设备的通讯协议进行分析可以帮助我们更好地理解其工作原理和相关技术,并且有助于以下几个方面: 1. 优化工业设备的通讯效率:了解通讯协议的细节可以帮助我们找到通讯效率低下的原因并进行优化,提高设备的通讯效率和…