聊聊mklink和它背后的NTFS链接机制
本文最后更新于40 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

起因:C盘又双叒叕告急了

事情是这样的。某天心血来潮拿扫盘软件看了眼C盘占用,结果发现Claude 10.9GB。旁边还挤着飞书9.7GB、腾讯系应用6.9GB

C盘从来不缺”占地大户”,缺的是官方迁移入口。像Docker Desktop这种成熟软件,设置里直接有”Disk image location”选项,点几下就能把数据挪到别的盘。但Claude Desktop、飞书这类应用没有——它们的数据目录死死焊在 C:\Users\你的用户名\AppData\Roaming\ 下面,软件本身完全不给你选路径的机会。

于是就有了这篇博文的主角:mklink /J

先搞清楚:什么是”链接”

一个文件在电脑里其实是两部分:数据本身(真正存在硬盘上的内容),和路径(比如 C:\Users\77619\Desktop\test.txt 这个字符串,用来告诉系统”去硬盘的这个位置读数据”)。

正常情况下,一个路径对应一份数据。你打开 C:\...\test.txt,系统就去硬盘上对应的位置读写,一一对应,没什么好想的。

链接做的事情,就是打破这个”一一对应”,让一个路径,实际指向另一个地方的数据。

具体到这次操作:Claude的数据本来存在 C:\Users\77619\AppData\Roaming\Claude 这个路径下。把真实数据剪切到 D:\AppData\Claude 之后,在原来 C:\...\Claude 这个路径上建了一个”联接”,让这个路径实际指向D盘的新位置。

之后任何程序(包括Claude Desktop本身)访问 C:\...\Claude 这个路径的时候,Windows系统会自动把访问请求转到 D:\AppData\Claude,程序拿到的数据是对的,但它自己不知道数据物理上其实在D盘。

mklink到底在干嘛

先说结论:mklink 是Windows自带的命令行工具,用来创建各种”链接”。而 /J 参数指的是其中一种类型——目录联接(Junction Point)

核心原理可以这么理解:它在文件系统层面制造了一个”障眼法”。创建联接之后,原来的路径(比如 C:\...\Claude)在Windows看来依然是一个正常的文件夹,图标上会多一个小箭头标志,但它实际上只是一个指针——所有对这个”文件夹”的读写操作,都会被系统自动重定向到真实存储的位置(比如 D:\AppData\Claude)。

关键在于,这种重定向发生在文件系统内核层面,而不是应用层面。程序本身完全不知道发生了什么,它以为自己在正常读写C盘,实际上数据物理存在D盘。杀毒软件、备份工具、甚至最底层的文件读写系统调用,都分辨不出这中间有一层转发。

和”快捷方式”完全是两码事

很多人第一反应会觉得,这不就是快捷方式吗?还真不是。

快捷方式(.lnk文件)是应用层的东西,只有支持解析这种文件的程序才认得——比如你在资源管理器里双击一个快捷方式,系统会读取里面记录的目标路径,然后帮你跳转过去。但如果换成一个不认识.lnk格式的程序,或者你在命令行里直接用路径去访问这个快捷方式文件,它就只是一个几KB的普通文件,压根不会自动跳转。

Junction不一样。它是NTFS文件系统原生支持的机制,不需要任何程序”认得”它,系统内核自己就完成了重定向。这也是为什么应用软件完全无感知——它甚至不知道自己被”骗”了。

mklink 就是Windows自带的命令,专门用来手动建立”路径A实际指向路径B”这种关系的。

Windows链接家族:三兄弟对比

为什么要分/J /D /H三种参数

因为链接可以作用在文件夹上,也可以作用在单个文件上,Windows底层处理这两种情况的技术不一样,所以命令要求你用不同参数指定”我现在要建哪种链接”。

mklink 命令其实支持好几种链接类型,容易搞混,这里做个对比:

参数名称作用对象是否需要管理员权限是否支持跨盘/跨机器
/J目录联接 Junction目录仅限本机磁盘
/D符号链接 Symbolic Link目录支持网络路径
/H硬链接 Hard Link文件仅限同一分区
(无参数)符号链接文件支持网络路径

/J(目录联接):这次实战用的就是它。历史很悠久,从Windows 2000时代就存在,最初是设计给系统内部用的机制,所以不需要管理员权限。缺点是只能指向本机的磁盘路径,没法指向网络共享文件夹。

/D(符号链接,针对目录):功能更强大,Vista之后才加入,权限管控更严格,因为设计上要支持指向网络路径这种更复杂的场景,微软出于安全考虑要求管理员权限才能创建。

/H(硬链接,针对文件):这个和前两者原理完全不同,前面说的都是”路径重定向”,硬链接则是让两个文件名直接指向同一块磁盘数据——本质上它们是同一份数据的两个入口,删掉其中一个文件名,只要另一个还在,数据就不会丢。但硬链接只能在同一个分区内创建,没法跨盘。

一个挺有意思的细节是,为什么/J不需要管理员权限而/D需要?这背后其实是NTFS文件系统权限模型设计的历史遗留问题——Junction诞生更早,设计定位更底层、更”系统内部”;Symbolic Link是后来加入的更现代化机制,因为要支持网络路径这种潜在的安全风险场景(比如恶意软件伪造链接指向敏感网络位置),微软收紧了权限要求。

扩展知识:不止Windows有这套东西

Linux/Mac的对应机制

bash

# 软链接(对应Windows的Symbolic Link)
ln -s /真实路径 /链接路径

# 硬链接(对应Windows的Hard Link)
ln /真实路径 /链接路径

Linux这边的设计更简洁——只分”软链接”和”硬链接”两种,没有Windows这种因为历史包袱分出来的Junction。

软链接既能指向目录,也能指向文件,还能跨分区(只要目标路径系统能访问就行)

不像Windows的Junction被限定只能用在目录上、只能本机磁盘。

不过如果你在WSL里用ln -s建了软链接,然后回到Windows这边用资源管理器去访问,很可能会发现根本打不开或者报错

因为WSL的Linux软链接和Windows原生的NTFS链接机制不是同一套东西,跨系统边界互相不认识。这也是为什么如果要在Windows和WSL之间共享数据目录,通常建议用Windows原生的挂载路径(/mnt/c/...这种),而不是指望链接能跨过去。

Git和链接的关系(顺便解释一个常见的误会)

之前有朋友问过我,Git是不是基于mklink这套机制做的

不是,完全没关系,值得单独说一下避免误会。

Git的核心机制是它自己实现的一套版本控制系统:每次提交,Git把文件内容做哈希计算,存成对象(object),记录变更历史和分支关系,这套数据结构和存储逻辑是Git自己造的轮子,跟操作系统的链接机制没有底层关联。

Git唯一跟”链接”沾边的地方是:它支持把符号链接本身当作一种被追踪的文件类型。

比如项目里有一个symlink,Git可以把这个”链接关系”本身记录进版本历史,别人拉取代码的时候能拿到同样的链接结构。但这只是Git支持追踪的众多文件类型之一,不代表Git的底层实现依赖这套机制。

Docker、数据库这些软件是怎么用链接的

日常开发中,链接机制其实无处不在,只是大部分时候被封装得看不见:

  • Docker容器的分层文件系统:Docker镜像那种”一层一层叠加”的存储方式,底层用到的Union File System,思路上跟链接有点像——多个层共享同一份基础数据,只有变更的部分单独存一份,避免每个容器都完整复制一份系统文件
  • 数据库软链接迁移:很多人给MySQL、PostgreSQL这类数据库搬家的时候,也是用同样的思路——把data目录整个搬到别的盘,原位置建软链接指回去,数据库服务本身完全无感知,这个套路本质上一模一样
  • Node.js的node_modules:如果你用过pnpm这种包管理器,会发现它默认用的就是硬链接机制来节省磁盘空间——同一个包如果被多个项目依赖,pnpm不会重复存储多份,而是让不同项目里的node_modules通过硬链接指向全局唯一的一份缓存

一个安全上的冷知识:符号链接攻击

链接机制虽然好用,但历史上也确实是安全漏洞的重灾区之一,统称”符号链接攻击”(Symlink Attack)。

简单原理是:如果一个程序以高权限运行,并且会写入一个用户可控的路径,攻击者可以提前在那个路径放一个指向敏感系统文件的符号链接,诱导高权限程序在不知情的情况下把内容写入到本不该被修改的系统文件里,达到提权或者破坏系统的目的。

这也是为什么现在很多安全规范会要求程序在写文件前先检查目标路径是不是链接、或者在权限设计上做额外限制——/D需要管理员权限这个设定,某种程度上也是出于类似的安全考虑,防止普通用户随便创建能指向敏感网络位置的链接。

写在最后

这次纯粹是被C盘10个G逼出来的一次探索,但顺手把Windows链接机制这块知识捋清楚了,感觉挺值。一次具体的场景,往往比死记文档更容易把原理刻进脑子里。

如果你也在被C盘空间困扰,而且手头正好有那么一两个”赖着不走”的软件数据目录,不妨试试这个法子。


本文基于Windows 10/11环境下的实际操作整理,NTFS文件系统机制细节部分建议进一步查阅微软官方文档做交叉验证。

文末附加内容

评论

  1. 博主
    Windows Chrome
    3 周前
    2026-8-20 0:09:59

    btw,不要把temp也迁移走,不然会出很多bug(。。

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇