背景

为什么我想研究这个呢!起先是我是我在研究nvm的时候,发现了符号连接这个东西。符号连接可以说是nvm实现版本切换的核心。在研究pnpm的时候,又发现pnpm对依赖树的处理也使用了硬连接和符号连接相结合的方式。对此,我对他俩产生了浓厚的兴趣,确实是我的知识盲区。

初识硬连接和符号连接

硬连接(hard link)和符号连接(symbolic link)在很多操作系统中都存在,他们由文件系统实现和支持,他们底层的实现原理可能存在大同小异,但是具体表现都是相同的。最初出现这个概念应该是在linux系统。但本文主要分析**windows**系统下硬连接和符号连接的实现。

硬连接

**其实文件管理器中的任何文件都是硬连接。**
这样一说的话,我感觉大家都蒙了。为什么,其实我感觉我们需要重新认识一下**文件**这个概念了。

重新认识文件

我们知道,我们是通过硬盘储存我们的文件,所以我们可能很容易的想当然认为文件就会像打开C盘那样的图像化界面一样放在C盘内。显然不是这样的,计算机的世界里只存在二进制,所以文件肯定是以二进制的形式存放在硬盘的某个位置。

比如我们存储一个**demo.txt**文件,这个时候文件系统就会生成一个文件ID,和我们存储的数据(比如这个**demo.txt**)进行一个一对一的绑定。文件ID在同一个卷中是唯一的。 但是,直到现在好像也没有图形化界面中那个可以点击的**demo.txt**什么事儿!下面关系就来了,文件ID和文件路径存在一个一对多的联系的。 当你新建一个**demo.txt**文件的时候,文件系统会在硬盘的一个区域写入这个文件,并且给这个区域分配一个文件ID,同时将**demo.txt**的路径和文件ID对应上。这样通过这个路径我们就可以定位到文件ID,从而定位到真正储存的数据了!!! 这个路径,对应的其实就是一个硬连接!!!所以我们常说的文件,其实就是一个硬连接。

我们可以通过系统内置的查找文件硬连接列表的命令印证自己想法:
**fsutil hardlink list [文件路径]**
image.png
所以我们常说的文件其实就是一个硬连接。

硬连接的特性

其实从我们之前的描述,也能推断出硬连接存在哪些特性。

  • 硬连接是和文件ID形成对应关系的,而文件ID只会在一个卷中才会是唯一的。(硬盘储存文件,是硬盘切割成卷来储存数据,文件系统赋予了数据同卷下独一无二的文件ID,关于卷和盘符的概念和区别,我还是很模糊。 所以硬连接和他指向的文件是在同一个卷下的。并且没人可以在一个卷中编辑另一个卷。(这里可以简单理解为硬连接只能指向同盘符下的文件。)
  • 文件ID和硬连接是一对多的关系的,但是至多1023个硬连接。
  • 不可以为目录创建硬连接,这样的话,目录的子文件的父亲就不会唯一。这会导致问题的。
  • 由于各个硬连接指向的文件ID是一致的,也就是数据是一致的,可以将硬连接理解成指针,所以从一个硬连接编辑文件,从另一个硬连接也会看到改变。所以也侧面反应,无论创建多少个硬连接,最终数据占据的空间是不会变的,因为始终只有一份数据。
  • 当删除硬连接时,如果数据还存在其他硬连接,换句话说,如果文件ID还有文件路径与之对应,那么这个数据就还能被访问到,那么它就不能被删除。反之,如果这个文件ID不存在与之对应的文件路径。那么这个数据就会被真正移除。这个其实就是文件系统维护的一个引用计数,不存在引用了,说明他就能被回收(删除)了。这个跟javascript中垃圾回收机制的一种方案,引用计数道理是一致的。
  • 移动硬连接或者改变硬连接的名称并不会导致硬连接的连接失效。

    硬连接的创建

    硬连接的创建,其实不像新建普通文件那样简单。存在两种方式:
  1. 通过命令行创建硬连接。
  2. 通过link shell extension创建硬连接。

    通过命令行创建硬连接

    New-Item [硬连接的名称] -ItemType HardLink -Target [目标文件的绝对路径]
    执行命令:New-Item hardlink.txt -ItemType HardLink -Target demo.txt
    image.png
    怎么证实他们指向同一个文件ID呢?
    我们可以使用命令行命令判断,指定文件路径指向哪个文件ID
    fsutil file queryFileID [文件路径]
    image.png

    通过link shell extension创建硬连接

    [link shell extension](https://schinagl.priv.at/nt/hardlinkshellext/hardlinkshellext.html)是一个强大的符号连接和硬连接的新建和管理工具。使用方法一共两种,第一种使用鼠标中键将目标文件拖拽到想要新建硬连接的文件夹: 1654165727297.mp4 (1.37MB)第二种,是右键目标文件点击”选择源连接点”,然后在新建硬连接的文件夹继续右键点击”创建为…” 1654165975172.mp4 (2.88MB)这个工具还会为硬连接添加一些实用选项卡:
    image.png
    我们可以在这个“连接属性”中获取几个关键信息:引用计数和文件ID与之对应的文件路径列表

    符号连接

    符号连接,符号连接跟硬连接存在本质的不同,符号连接实际上和快捷方式有点类似。符号连接的主要原理是这样的:

    符号连接本身和一个数据对应,或者说他对应一个内存区域(文件ID),这个内存区域其实储存的就是一个路径。然后文件系统就会去访问这个路径对应的资源。

所以,从这点描述上我们就可以知道,符号连接对应的文件ID和目标文件的文件ID肯定是不同的。符号连接的文件ID对应的内存区域储存目标文件的文件路径,而目标文件的文件ID对应的储存区域储存目标文件。
所以,我们生成符号连接的时候,必须要提供一个文件路径。

符号连接的特性

  • 符号连接可以指向任何文件或者文件夹,因为符号连接指向的内存区域当然可以存储任何路径了!文件路径,文件夹路径,甚至可以给他提供一个不存在路径。
  • 对符号连接连接的文件做的任何操作都是会作用到目标文件上的,因为操作的就是目标文件本身
  • 对目标文件进行移动,改名会使得符号连接的连接失效,这也是容易理解的,当做了如上操作之后,符号连接指向的内存区域储存的路径自然是一个错误的路径了。
  • 对符号连接进行删除,并不会影响目标文件,影响的反而是符号连接本身。这样的话,导致符号连接指向的内存区域由于没有被任何文件路径引用,而被删除。

    创建符号连接

    通过命令行创建符号连接

    New-Item [软连接的名称] -ItemType SymbolicLink -Target [目标文件的绝对路径]
    符号连接的创建需要开启管理员权限!!!

    通过link shell extension创建符号连接

    过程同硬连接的创建
    同样的这个工具也给符号连接提供了有用的信息展示项,记录了连接的目标:
    image.png

    符号连接和快捷方式的区别

    其实,符号连接和快捷方式有很多相似的地方。比如说,他们都有目标路径,他们的删除都对目标不会产生任何影响。但是他们存在些许的不同。

    快捷方式本质上是一个文件,后缀名以.lnk结尾。这个文件储存了目标文件的路径,所以他本身具有一定大小。 符号连接并不局限于以某个特定的后缀名结尾,符号连接可以是.txt,.docx,都有可能。本身是不具备大小的。 此外,快捷方式必须使用绝对路径,而符号连接可以使用相对路径和绝对路径。

给符号连接创建硬连接

突然灵光一现,我想给符号连接创建一个硬连接会导致什么样的情况。
这种情况下,不会创建出硬链接,而会创建出一个符号连接:
image.png
并且他们指向的内存数据是一致的。

软连接

其实,在别的文件系统中,软连接和符号连接(symbolic link)是一个概念,但是在windows的文件系统中,他们是不一样的概念。因为在windows引入symbolic link之前出现过一种和symbolic link的功能十分类似的连接,他的名字叫junctions。所以他就先入为主的称为了软连接(soft link)。

windows中的连接种类 中文名字
junctions 软连接(又称目录连接)
symbolic link 符号连接
hard link 硬连接

其实,windows的软连接和符号连接,从原理和表现上看都是非常类似的。(软连接同样可以跨卷)主要区别可能是这几点:

  1. 软连接的目标文件只能是目录,而符号连接的目标文件可以是目录,文件。
  2. 软连接只能使用绝对路径,而符号连接可以使用相对路径。
  3. 软连接不能跨主机,但是符号连接可以跨主机。
  4. 软连接出现时间(windows 2000/ xp)比符号连接(windows vista)更早,所以软连接的兼容性更好。

    参考文章