当前位置: 首页 > article >正文

基础 IO(文件系统 inode 软硬链接)-- 详解

目录

  • 一、理解文件系统
    • 1、前言
    • 2、磁盘
      • (1)理解过程
      • (2)真实过程
    • 3、磁盘分区与格式化介绍
      • (1)磁盘分区
      • (2)磁盘格式化
      • (3)EXT2文件系统的存储方案
      • (4)一些问题
  • 二、软硬链接
    • 1、软链接
    • 2、硬链接

一、理解文件系统

1、前言

我们一直都在说打开的文件,磁盘中包含了上百万个文件,肯定不可能都是以打开的方式存在。其实文件包含打开的文件和普通的未打开的文件,下面重点谈谈未打开的文件。

我们知道打开的文件是通过操作系统被进程打开,一旦打开,操作系统就要维护多个文件,所以它是需要被操作系统管理的。也就是说这种方式,磁盘上和内存上都有这个文件,它们不是完全一样的,内存中的文件更强调的是属性和方法,磁盘中的文件更强调的是数据,它们是通过缓冲区关联的;而普通的未打开的文件在磁盘上,未被加载到内存中,它当然也要被管理;其中管理打开的文件和管理未打开的文件在操作系统中有一个功能模块叫做文件系统

之前我们谈过进程 VS 程序,一个被打开的程序就是进程,只不过我们在解释进程时不是严格地把它当作文件来解释,需要明白的是进程是要被加载到内存的,程序就是一个磁盘文件,打开的文件是进程,而普通未打开的文件是程序

在这里插入图片描述
内存文件我们之前已经讲过,现在来讲磁盘文件。磁盘文件由两部分构成,分别是文件内容和文件属性。文件内容就是文件当中存储的数据,文件属性就是文件的一些基本信息,例如文件名、文件大小以及文件创建时间等信息都是文件属性,文件属性又被称为元信息。

在命令行当中输入ls -l,即可显示当前目录下各文件的属性信息。
在这里插入图片描述
ls -l 读取存储在磁盘上的文件信息,然后显示出来
在这里插入图片描述
这里在命令行上输入 ls -l,bash 解析 ls -l,fork 创建子进程,让子进程通过进程替换执行 ls -l,ls -l 会在当前路径下把文件的属性通过磁盘读到内核,再由内核读到用户空间显示出来。 其实这个信息除了通过这种方式来读取,还有一个 stat 命令能够查看更详细的信息。
在这里插入图片描述
如果不深入的话,这块也没什么价值,谁不知道文件在磁盘上,ls -l 读取当前路径下文件的属性,所以我们还要研究它的原理。

但是在此之前,我们需要先认识磁盘,关于磁盘这个话题,还会在数据库中再讲一次。

2、磁盘

(1)理解过程

内存 – 掉电易失存储介质
磁盘 – 永久性存储介质 – SSD、U盘、flash卡、光盘、磁带

众所周知,磁盘分为机械硬盘(HDD)和固态硬盘(SSD),现在很多的电脑都是机械硬盘和固态硬盘组合使用,但服务器上大多都是机械硬盘,只有一些高效率的存储集群会用到固态硬盘。机械硬盘和固态硬盘在存储技术上肯定是不同的,而我们主要了解机械硬盘,因为它多用于服务器上,其次虽然固态硬盘要比机械硬盘快不少,但在 CPU 看来,两者都很慢,我们这里就了解最慢的。
在这里插入图片描述

如下图,虽然磁盘的盘面看起来很光滑,但是它上面有一些同心圆,这些同心圆用圆白线划分,每一圈叫做磁道,数据写在这些有颜色的区域上。实际上你并不是把一圈的空间都用完,所以这里还使用了一些直白线划分,被圆白线和直白线划分出来的区域叫做扇区。所以当盘片在旋转、磁头摆动就可以找到这个盘片的任何一个扇区进行读写。 实际磁头和盘面并不是接触的,它们之间的距离就像一架飞机在离平地 1 米的距离滑行,所以如果笔记本摔了或者是在开机状态下总被搬来搬去,磁头就容易与盘片接触,此时就有可能会刮花盘片,电脑就可能会发生蓝屏等。

在这里插入图片描述
盘面是有两面的,且两面都是同心圆,数据只能写在同心圆(磁道)上,根据配置不同,有些磁盘可能还有多组盘片,我们可以从上至下的分为不同的盘面,也叫做你是第几个盘面。
在这里插入图片描述
虽然在 C 语言中访问内存的基本单位是 1byte ,但是在操作系统的角度认为内存的基本单位一般是 4kb,在操作系统看来,内存就是一个数组,每一个元素是 4kb。

之前在谈进程地址空间时也说过它叫做页框,4kb 是页帧,所以操作系统申请内存时是按 4kb 为单位进行分配和加载的,语言层面上并不关心底层是怎么做的,比如你要 malloc 1byte,那么操作系统也不可能直接给你 4kb,有可能 C 语言本身就缓冲了一部分空间让你去使用,如果超出这一部分空间,操作系统再重新分配。

磁盘存储的基本单位是一个扇区,它是磁盘读取的最小单元,大部分磁盘的一个扇区是 512byte,但你会发现虽然这里好像越靠近圆心,扇区越小,其实它们都是 512byte,原因是越靠近圆心的虽然扇区越小,但是比特位也相对外圈更密集。内存和磁盘之间也是有交互的,它们之间的交互我们称为 output、input,也叫做 IO,一般内存和磁盘之间 IO 交互时,不是纯硬件级别的交互,而是要通过文件系统完成,也就是通过操作系统。

这里用户和内存之间交互的基本单元大小是 1byte,一般内存和磁盘之间交互时的基本单元大小是 4kb,所以文件系统在往磁盘读数据时,要读 8 个扇区,这就是数据由磁盘加载到内存的过程。

将数据存储到磁盘 --> 将数据存储到该数组
找到磁盘特定扇区的位置 --> 找到数组特定的位置
对磁盘的管理 --> 对该数组的管理

在这里插入图片描述
其中我们再选取 stat 中展示的一部分信息,我们将内存和磁盘之间交互时的基本单元大小 4kb 叫 Blocks,这里的 IO Block:4096 就是 8 × 512。
在这里插入图片描述


一般像这样的机械硬盘在物理上是圆状,操作系统很难去管理它,因为操作系统如果不对它进行抽象化处理,那么操作系统中的代码可能就是 read(盘面,磁道,扇区),操作系统需要知道这三个参数的话,那么一定要在操作系统读取磁盘的代码中以硬编码的形式写到操作系统中。

但是如果有一天,你给自己的电脑加了一块固态硬盘,你要对固态硬盘进行读操作,就不能再用以前的方法了,因为固态硬盘与机械硬盘的结构不一样,它没有盘面、磁道、扇区,所以操作系统中曾经设计好的代码就得修改。很显然,这样的设计导致它们之间出现了强耦合,这是很不合理的。
在这里插入图片描述


所以需要对磁盘抽象化处理,将圆状结构的磁盘空间抽象成线性结构的磁盘空间。这里举两个例子方便理解:

  1. 其实在 C 语言中我们见过的 int arr[3][4] 二维数组就是把线性的数据结构抽象成了好理解的有行有列的结构。
  2. 磁带,是把数据存储于那条黑色的带子上,可能是为了空间的原因,把带子卷起来形成一个圆状,所以磁带在物理上,既可以是圆状,也可以是线状。

在这里插入图片描述

同样的,也能把磁盘抽象成线性结构。把磁盘上的磁道抽象成线性形状,比如磁盘的所有磁道被我们抽象成了一条 500GB 的线性空间,我们可以把它看作一个很大的数组 —— 扇区 array[NUM],其中每一个元素是 512byte,操作系统要申请 4kb,那就给数组的 8 个元素。所以将磁盘抽象后,操作系统就摆脱盘面、磁道、扇区的束缚了,操作系统只关心你想访问的哪个下标,这里的地址我们称为逻辑区块地址(Logical Block Address, LBA),这里抽象出来的数组下标是和机械硬盘中盘面、磁道、扇区构成映射关系的,这里的映射关系是由对应的机械磁盘驱动维护的,操作系统想往 2 下标处写数据,最终 2 下标一定是能对应到具体磁盘中某个扇区上。如果要往固态硬盘中写数据,也是把它抽象成线性的数组,它也有自己的固态硬盘驱动维护数组下标和固态硬盘之间的映射关系。至此,通过抽象的方法,就完成了操作系统和磁盘之间的解耦。所以最终操作系统对磁盘的管理,转换成了对数组的管理。
在这里插入图片描述

一块磁盘,有很多盘面,盘面都一样,数组元素个数都一样
在这里插入图片描述

为什么操作系统(文件系统)和磁盘不以 512byte 为单位呢?

太小了,可能会导致多次 IO,进而导致效率的降低。
如果操作系统使用和磁盘一样的大小,万一磁盘的基本大小发生改变,那 OS 的源代码要不要改呢?那岂不是将硬件和软件(OS)进行解耦。

(2)真实过程

一个细节:传动臂上的磁头是共进退的
在这里插入图片描述
柱面是一个逻辑上的概念,其实就是每一面上,相同半径的磁道逻辑上构成柱面。
所以,磁盘物理上分了很多面,但是在我们看来,逻辑上,磁盘整体是由“柱面”卷起来的。
在这里插入图片描述
所以,磁盘的真实情况是:

磁道:
某一盘面的某一个磁道展开:
在这里插入图片描述
即:一维数组

柱面:
整个磁盘所有盘面的同一个磁道,即柱面展开:

在这里插入图片描述

  • 柱面上的每个磁道,扇区个数是一样的
  • 这不就是二维数组吗

整盘:
在这里插入图片描述
整个磁盘不就是多张二维的扇区数组表(三维数组)

所以,有定位扇区的方法:CHS地址定位

  1. 可以先定位磁头(header)
  2. 确定磁头要访问哪一个柱面(磁道)(cylinder)
  3. 定位一个扇区(sector)
  4. CHS地址定位

我们之前学过C/C++的数组,在我们看来,其实全部都是一维数组:
在这里插入图片描述
所以,每一个扇区都有一个下标,我们叫做LBA(Logical Block Address)地址,其实就是线性地址,所以怎么计算得到这个LBA地址呢?

CHS转成LBA:

  • 磁头数 * 每磁道扇区数 = 单个柱面的扇区总数
  • LBA = 柱面号C * 单个柱面的扇区总数 + 磁头号H * 每磁道扇区数 + 扇区号S - 1
  • 即:LBA = 柱面号C * (磁头数*每磁道扇区数) + 磁头号H * 每磁道扇区数+扇区号S - 1
  • 扇区号通常是从1开始的,而在LBA中,地址是从0开始的
  • 柱面和磁道都是从0开始编号的
  • 总柱面,磁道个数,扇区总数等信息,在磁盘内部会自动维护,上层开机的时候,会获取到这些参数。

LBA转成CHS:

  • 柱面号H =LBA //(磁头数*每磁道扇区数)【就是单个柱面的扇区总数】
  • 磁头号 =(LBA %(磁头数*每磁道扇区数)) // 每磁道扇区数
  • 扇区号 =(LBA % 每磁道扇区数) + 1
  • “//”:表示除取整

所以:从此往后,在磁盘使用者看来,根本就不关心CHS地址,而是直接使用LBA地址,磁盘内部自己转换。
所以:从现在开始,磁盘就是一个 元素为扇区 的一维数组,数组的下标就是每一个扇区的LBA地址。OS使用磁盘,就可以用一个数字访问磁盘扇区了。

3、磁盘分区与格式化介绍

线性存储介质

理解文件系统,首先我们必须将磁盘想象成一个线性的存储介质,想想磁带,当磁带被卷起来时,其就像磁盘一样是圆形的,但当我们把磁带拉直后,其就是线性的。

(1)磁盘分区

磁盘通常被称为块设备,一般以扇区为单位,一个扇区的大小通常为512字节。我们若以大小为512G的磁盘为例,该磁盘就可被分为十亿多个扇区。

在这里插入图片描述
计算机为了更好的管理磁盘,于是对磁盘进行了分区。磁盘分区就是使用分区编辑器在磁盘上划分几个逻辑部分,盘片一旦划分成数个分区,不同的目录与文件就可以存储进不同的分区,分区越多,就可以将文件的性质区分得越细,按照更为细分的性质,存储在不同的地方以管理文件,例如在Windows下磁盘一般被分为C盘和D盘两个区域。

在Linux操作系统中,我们也可以通过以下命令查看我们磁盘的分区信息:

syc@VM-4-17-ubuntu:~/linux$ sudo ls /dev/vda* -l

在这里插入图片描述

(2)磁盘格式化

当磁盘完成分区后,我们还需要对磁盘进行格式化。磁盘格式化就是对磁盘中的分区进行初始化的一种操作,这种操作通常会导致现有的磁盘或分区中所有的文件被清除。
简单来说,磁盘格式化就是对分区后的各个区域写入对应的管理信息。
在这里插入图片描述

其中,写入的管理信息是什么是由文件系统决定的,不同的文件系统格式化时写入的管理信息是不同的,常见的文件系统有EXT2、EXT3、XFS、NTFS等。

(3)EXT2文件系统的存储方案

计算机为了更好的管理磁盘,会对磁盘进行分区。而对于每一个分区来说,分区的头部会包括一个启动块(Boot Block),对于该分区的其余区域,EXT2文件系统会根据分区的大小将其划分为一个个的块组(Block Group)。
在这里插入图片描述

注意: 启动块的大小是确定的,而块组的大小是由格式化的时候确定的,并且不可以更改。

其次,每个组块都有着相同的组成结构,每个组块都由超级块(Super Block)、块组描述符表(Group Descriptor Table)、块位图(Block Bitmap)、inode位图(inode Bitmap)、inode表(inode Table)以及数据表(Data Block)组成。
在这里插入图片描述

  1. Block Group:ext2 文件系统会根据分区的大小划分为数 个Block Group,而每个 Block Group 都有着相同的结构组成。
  2. 超级块(Super Block):是文件系统的核心结构,用于存放文件系统本身的结构信息,描述文件系统的属性信息,记录的信息主要有:bolck 和 inode的总量,未使用的 block 和 inode 的数量,一个 block 和 inode 的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。一般计算机启动时,Super Block 会被加载到操作系统,其中每一块组好像都有一个 Super Block,但实际可能 10 个块组中只有两三个有 Super Block。如果 Super Block 的信息被破坏,可以说整文件系统结构就被破坏了。
  3. Group Descriptor Table(GDT):块组描述符。Super Block 描述的是整个块组相关的信息,这里描述的是一组的属性信息,每一个块组都必需要有一个 Group Descriptor Table。
  4. 块位图(Block Bitmap):Block Bitmap 中记录着 Data Block 中哪个数据块已经被占用,哪个数据块没有被占用。其中比特位为 1 表示该 block 被占用,否则表示可用。
  5. inode 位图(inode Bitmap):每个 bit 表示一个 inode 是否空闲可用,比特位和特定的 inode 是一一对应的。其中,inode bitmap 中比特为 1 表示该 indoe 被占用,否则表示可用。
  6. inode Table(节点表):存放文件属性,即每个文件的inode编号(节点编号),类似PID、文件大小、所有者、最近修改时间等。
  7. Data Blocks(数据区):存放文件内容。

我们说过文件 = 内容 + 属性。这里的内容和属性采用分离存储:
8. 属性放在 inode Table 中。一个组中可以放多少个 inode 是一定的,基本上一个文件或目录一个 inode,inode 是一个文件的所有属性集合,属性也是数据,也要占用空间。所以即便是一个空文件也要占用空间,这里的属性集合包含文件权限、大小等,但不包含文件名。

  1. 内容放在 Date blocks 中。比如这里的块组是 10G,那么 inode Table 占 1G,Date blocks 占了 8G, 一个 inode 是 512byte,粗略的算一下,1G 大概 42 亿多字节,除以 512 大概也有几千万,所以这样一个块组能保存几千万文件的 inode 信息。这里 inode Table 和 Data blocks 的划分可能会出现你用完了、我没用完,或者你没用完、我用完了的情况,这种情况并没有有效的方法解决。

Date blocks 相当于一个数据块集合,报错的都是特定文件的内容,它以 4k 为单位(Date blocks 可以理解成多个 4kb(扇区*8)大小的集合),对应的数据块属于哪些文件,是由 Data Blocks 和 inode Table 维护的。如下图,inode Table 是一个大小为 128字节的空间,包含了若干大小相同的块,这些块有不同的编号,对应就是对应文件的属性,Data blocks 也包含了若干大小相同的块,这些块也有不同的编号,对应就是文件的内容。此时新建文件或目录,就给文件申请 1 号 inode,并把文件的各种属性写入到 1 号 inode,1 号 inode 中包含了一个数组 block b[32],比如 1 号 inode 需要 2 个数据块,所以 [0] = 2,[1] = 3,所以 1 号 inode 就可以找到对应的数据块。换而言之,要在磁盘上查找一个文件,我们只需要知道这个文件的 inode 是多少,因为 inode 需要标识唯一性,每一个 inode 块都要有一个 inode 编号,至此,我们知道真正标识文件的不是文件名,而是文件的 inode 编号。既然 inode 大小是确定的,万一文件是 10 个 T,此时数据块就不够了,文件系统的处理策略是数据块不仅可以保存数据的内容,还可以保存其它数据块的编号,它类似于 b+ 树。换言之,对于保存较大的文件,可能就需要多级索引的形式。

在这里插入图片描述
找到文件:inode 编号 -> 分区特定的 BlockGroup -> inode -> 属性 -> 内容

目录是文件吗?

是。目录有自己的 inode 和自己的 data block,data block 存储的是文件名和对应的 inode 编号的映射关系,两者互为 key 值。


这里 ls - i 就可以查看文件或目录对应的 inode 了,可以看到这里的 inode 并不是严格连续申请的,它依然能看到文件名,是因为我们需要识别。
在这里插入图片描述
注意:

  1. 其他块组当中可能会存在冗余的Super Block,当某一Super Block被破坏后可以通过其他Super Block进行恢复。
  2. 磁盘分区并格式化后,每个分区的inode个数,block个数就确定了。
  3. inode分配的时候,只需要确定起始 inode 即可,起始inode和起始block存在GDT里。

(4)一些问题

问题1:我们如何分配 inode 的?

inode = inode Bitmap+ start_inode。所以真实的inode值假如是3+起始的inode1,等于4。

问题2:我们如何分配 block 的?

与上述相同,block = data block + start_block。

问题3:操作系统如何管理文件系统?

先描述再组织。我们有这么多分区,就有这么多Super Block,GDT…,我们把这些Super Block,GDT…加载到内存里,构成struct对象,然后把他们以链表形式管理起来,就可以把文件系统的管理转变成了对链表的增删查改。

问题4:如何查找一个文件?
首先根据inode号区间确定在哪一个组里面,通过GDT查到对应组的start_inode,再根据inode Bitmap + start_inode 得到 inode,再到inode Table里根据inode找到属性,也就得到了属性和block的映射关系,所以得到了块号,类似的方式就可以找到内容,也就查到了文件。

问题5:如何删除一个文件?

  1. 将该文件对应的inode在inode位图当中置为无效。
  2. 将该文件申请过的数据块在块位图当中置为无效。

因为此操作并不会真正将文件对应的信息删除,而只是将其inode号和数据块号置为了无效,所以当我们删除文件后短时间内是可以恢复的。
为什么说是短时间内呢,因为该文件对应的inode号和数据块号已经被置为了无效,因此后续创建其他文件或是对其他文件进行写入操作申请inode号和数据块号时,可能会将该置为无效了的inode号和数据块号分配出去,此时删除文件的数据就会被覆盖,也就无法恢复文件了。

问题6:为什么拷贝文件的时候很慢,而删除文件的时候很快?
因为拷贝文件需要先创建文件,然后再对该文件进行写入操作,该过程需要先申请inode号并填入文件的属性信息,之后还需要再申请数据块号,最后才能进行文件内容的数据拷贝,而删除文件只需将对应文件的inode号和数据块号置为无效即可,无需真正的删除文件,因此拷贝文件是很慢的,而删除文件是很快的。

这就像建楼一样,我们需要很长时间才能建好一栋楼,而我们若是想拆除一栋楼,只需在这栋楼上写上一个“拆”字即可。

问题6:如何修改一个文件?
先拿着inode查找。如果改文件属性,就查找到属性,然后把inode加载到内存里,改完在写回来;如果改文件内容,就找到block,把磁盘内容加载到内核级缓冲区,改完再写回来。

问题7:如何新增一个文件?
通过遍历inode位图的方式,找到一个空闲的inode。
在inode Table当中找到对应的inode,并将文件的属性信息填充进inode结构中。
将该文件的文件名和inode指针添加到目录文件的数据块中。
给用户返回inode Bitmap+ start_inode。

子问题1:inode 和 block 究竟怎么映射的
在这里插入图片描述
一个文件块4kb。

子问题2

  1. 凭什么拿到inode?我们访问的好像就是文件名啊!其中,Linux中,文件名不在Inode中保存。(与问题2一起回答)

  2. 如何理解目录文件?
    我们之前说过目录 = inode + datablock = 属性 + 内容 ,因此内容就是会有对应的数据块,数据块里存的是文件名和inode的映射关系。因此就通过文件名根据映射关系找到了inode,通过inode进行查找文件等操作。

  3. 怎么理解目录权限?
    权限rwx,假如没有读权限,目录就读不到data blocks,就拿不到文件名和inode的映射关系,就得不到inode,因此就无法访问文件。假如没有写权限,就无法把文件名和inode的映射关系这样的字符串信息写到目录数据块里。没有执行权限,进不去文件的本质是打不开。

但是其中出现了一个问题:找到文件名,首先要打开当前目录,但是当前目录也是一个文件,也有自己的文件名,于是要找到更上一层目录,更上一层目录也同样是一个文件…

所以要进行一个逆向的路径解析,举例:

在这里插入图片描述
比如今天我们要查找test.txt 就要找到lesson21,但是只知道lessons21的名字,我们需要找到数据块datablock,从而找到test.txt的文件名与inode的映射关系,进行文件查找,但是要找到lesson21,就需要先打开code这个目录,找到code的数据块,从而找到lesson21的文件名与inode的映射关系,因此要找到code,就要先打开112这个目录,一层一层往前,最后home找根目录,根目录就是固定的了。

  1. 为什么任何一个文件,都要有路径?
    因为没有路径,就根本不可能找到文件,文件名和inode映射关系根本建立不起来。因此必须要有全路径,根据全路径,在linux系统内部进行路径解析,才能找到映射关系,找到文件。
    所以每个进程都有一个cwd,这样无论传入任何目标文件,都有路径。

  2. linux中假如要找test.txt,第二次再找,难道要根据目录再推一遍吗?
    不用。linux系统,需要进行对路径结构进行缓存。
    但是以什么结果缓存我们的操作路径呢?
    多叉树。他会把用户曾经访问过的目录构建成节点缓存起来, 第二次访问直接查找缓存结构

在这里插入图片描述
task_struct里的file找到文件描述符表,找到里面的path,找到里面的dentry,找到里面的inode。

问题8:怎么确认我们在哪一个分区里?
Linux系统中,假如有多个分区,那么必须要有一个分区包含根目录,系统一开始就要找到他。还要有多干个普通目录,分区必须经过“挂载”到目录上,分区才可以被用通过路径的方式进行访问,只有分区,该分区无法直接使用。

先看小实验:
查看有多少分区命令:ls /dev/vda*
在这里插入图片描述
查看磁盘对应的详细情况命令:df -h
在这里插入图片描述
tmpfs是模拟出来的内存级的分区,我们不用管。我们看/dev/vda2,Mounted on 是被挂载到的意思,/dev/vda2被挂载到了根目录。
形成一个大的临时文件的命令:dd if=/dev/zero of=./disk.iso bs=1M count=5
在这里插入图片描述

我们把这个大文件当做一个磁盘空间,然后写入文件系统
在这里插入图片描述

disk.iso就是我们的临时分区。
然后我们创建一个目录
在这里插入图片描述
我们把disk.iso挂载到该目录下
在这里插入图片描述
现在我们就可以在该分区中创建文件目录等操作,看似是在目录myvda2中,实际在disk.iso中。
在这里插入图片描述
当然也可以退回当更上层目录,删掉此分区
在这里插入图片描述

此时做完小实验,我们来回答怎么确认我们在哪一个分区里?
访问任何一个文件,都要有路径。路径的前缀就可以指明你在哪一个分区下。

二、软硬链接

1、软链接

我们可以通过以下命令创建一个文件的软连接。

syc@VM-4-17-ubuntu:~/linux/lesson22$ ln -s file.txt file-soft.link

在这里插入图片描述

通过ls -i -l命令我们可以看到,软链接文件的inode号与源文件的inode号是不同的,并且软链接文件的大小比源文件的大小要小得多。

在这里插入图片描述

软链接又叫做符号链接,软链接文件相对于源文件来说是一个独立的文件,该文件有自己的inode号,但是该文件只包含了源文件的路径名,所以软链接文件的大小要比源文件小得多。软链接就类似于Windows操作系统当中的快捷方式。

在这里插入图片描述

但是软链接文件只是其源文件的一个标记,当删除了源文件后,链接文件不能独立存在,虽然仍保留文件名,但却不能执行或是查看软链接的内容了。

在这里插入图片描述

2、硬链接

我们可以通过以下命令创建一个文件的硬连接。

syc@VM-4-17-ubuntu:~/linux/lesson22$ ln file.txt file-hard.link

在这里插入图片描述

通过ls -i -l命令我们可以看到,硬链接文件的inode号与源文件的inode号是相同的,并且硬链接文件的大小与源文件的大小也是相同的,特别注意的是,当创建了一个硬链接文件后,该硬链接文件和源文件的硬链接数都变成了2

在这里插入图片描述

硬链接文件就是源文件的一个别名一个文件有几个文件名,该文件的硬链接数就是几,这里inode号为547419的文件有file.txt和file-hard.link 两个文件名,因此该文件的硬链接数为2。

与软连接不同的是,当硬链接的源文件被删除后,硬链接文件仍能正常执行,只是文件的链接数减少了一个,因为此时该文件的文件名少了一个。

在这里插入图片描述

总之,硬链接就是让多个不在或者同在一个目录下的文件名,同时能够修改同一个文件,其中一个修改后,所有与其有硬链接的文件都一起修改了。

为什么刚刚创建的目录的硬链接数是2?

我们创建一个普通文件,该普通文件的硬链接数是1,因为此时该文件只有一个文件名。
那为什么我们创建一个目录后,该目录的硬链接数是2?

在这里插入图片描述

因为每个目录创建后,该目录下默认会有两个隐含文件.和…,它们分别代表当前目录和上级目录,因此这里创建的目录有两个名字,一个是dir另一个就是该目录下的.,所以刚创建的目录硬链接数是2。通过命令我们也可以看到dir和该目录下的 . 的inode号是一样的,也就可以说明它们代表的实际上是同一个文件

在这里插入图片描述

如果在dir目录下再创建一个目录dir1

在这里插入图片描述

注: Linux中不允许对目录新建硬链接!

在这里插入图片描述

对目录硬链接会形成环。
假如/a/b/c/d/e 一条目录,e与c进行硬链接,进到e就会跳到c,形成闭环,出来就难了。


http://www.kler.cn/a/382276.html

相关文章:

  • C#在自定义事件里传递数据
  • 【工作流】工作顺序
  • LabVIEW实现WiFi通信
  • c++ ------语句
  • 使用Vscode+EIDE+Jlink开发STM32环境配置教程
  • 探索 CI/CD 工具的力量
  • 从SSL到TLS——互联网传输的护卫军
  • 程序中怎样用最简单方法实现写excel文档
  • Dubbo详解及其应用
  • SpringBoot在线教育系统:微服务架构
  • EPSON机械手与第三方相机的校准功能设计By python
  • 高亚科技签约酸动力,助力研发管理数字化升级
  • 【制造业&仓库】流水线能源设备检测系统源码&数据集全套:改进yolo11-DCNV2-Dynamic
  • 【Golang】Golang的Map的线程安全问题
  • 01 Oracle 数据库存储结构深度解析:从数据文件到性能优化的全链路探究
  • 【论文速看】DL最新进展20241106-图像分类、图像分割、时间序列预测
  • 【p2p、分布式,区块链笔记 Torrent】WebTorrent的add和seed函数
  • 数字后端零基础入门系列 | Innovus零基础LAB学习Day8
  • 【vue-pdf】简单封装pdf预览组件
  • Linux信号_信号的保存
  • 应用层知识点总结2
  • 华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目——共8套(每套四十题)
  • 一文了解CANFD基础
  • 5种AI合同审查方法,免费开源,提升50%法律文件比对效率
  • 在 hiveSQL 中判断一个字段是否包含某个值
  • 基于STM32的智能水族箱控制系统设计