这次本来不是为了折腾微信。

起因很简单:我要在 Mac 上装完整 Xcode 和 iOS Simulator,本机系统盘空间不够。一路查下来,发现微信的数据目录占了几十 GB:

~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files

这个目录里是微信 Mac 版的聊天文件、图片、视频、缓存和各种历史数据。它不声不响长到几十 G,非常合理,也非常要命。

第一反应:搬到外置盘,再软链接回来

最直觉的方案是:

  1. 退出微信
  2. xwechat_files 复制到外置盘
  3. 原目录改名备份
  4. 在原位置建一个软链接,指向外置盘目录
  5. 打开微信测试

大概长这样:

mv ~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files \
  ~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files.backup

ln -s /Volumes/<ExternalDrive>/AppData/WeChat/xwechat_files \
  ~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files

但这条路在我这里失败了。

微信打开后能看到目录,却提示很多文件丢失。也就是说,对于微信这种沙盒 App,特别是 ~/Library/Containers/... 下面的数据目录,软链接不一定能被它按预期处理。可能和沙盒权限、文件安全策略、App 内部路径判断都有关系。总之结论很明确:不要以为软链接一定透明

这一步幸好只是测试,没有删原数据,才能安全回滚。

最终方案:把 APFS 卷挂载到微信原目录

后来换了一个思路:不让微信感知“目录被搬走了”,而是让原目录本身变成一个挂载点。

也就是:

微信仍然访问:
~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files

但这个路径背后实际挂载的是外置盘上的 APFS 卷:
WeChatData

这样做的好处是:

  • 对微信来说,路径没有变
  • 新产生的文件会继续写到这个挂载卷里
  • 不需要依赖软链接
  • APFS 卷可以在同一个 APFS 容器内动态使用剩余空间
  • 系统盘可以真正释放掉那几十 G

最终状态类似这样:

/dev/diskXsY on /Users/<username>/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files \
  (apfs, local, nodev, nosuid, journaled, noowners)

这里的 diskXsY 代表新建 APFS 卷对应的设备标识。每个人的磁盘编号都不一样,不要照抄。

实际操作流程

下面是我这次采用的流程。重点不是每条命令原样复制,而是顺序和安全边界。

1. 先完整备份

先退出微信,然后把原始目录完整复制到外置盘。

SRC="$HOME/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files"
DST="/Volumes/<ExternalDrive>/AppData/WeChat/xwechat_files"

mkdir -p "$(dirname "$DST")"
rsync -aE "$SRC/" "$DST/"

-aE 是为了尽量保留 macOS 文件属性。微信数据这类目录,不建议用最普通的复制方式草草搬完。

复制完成后,不要急着删系统盘上的原目录。先留着。

2. 在外置盘 APFS 容器里新建卷

先用 diskutil list 找到外置盘所在的 APFS container。外置盘所在的容器可能类似 diskX,所以新建卷类似这样:

diskutil apfs addVolume diskX APFS WeChatData

新卷建好后,可以看它的标识和 UUID:

diskutil info WeChatData

示例输出类似这样:

Volume Name: WeChatData
Device Identifier: diskXsY
Volume UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

这些值只是示例,不是通用参数。

3. 把备份数据复制进新卷

新卷默认会挂载在:

/Volumes/<WeChatData>

然后把刚才备份出来的数据复制进去:

rsync -aE "/Volumes/<ExternalDrive>/AppData/WeChat/xwechat_files/" "/Volumes/<WeChatData>/"

这里我保留了两份:

  • /Volumes/<ExternalDrive>/AppData/WeChat/xwechat_files:最开始复制出来的完整备份
  • /Volumes/<WeChatData>:真正准备给微信使用的 APFS 卷

这一步有点占空间,但在确认微信正常之前,多一份备份很值。

4. 把 APFS 卷挂载到微信原目录

确认微信已经退出后,把系统盘上的原目录改名成临时备份:

WECHAT_DIR="$HOME/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files"

mv "$WECHAT_DIR" "$WECHAT_DIR.backup-apfs-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$WECHAT_DIR"

然后把 WeChatData 挂载到这个空目录上:

diskutil unmount WeChatData
diskutil mount -mountPoint "$WECHAT_DIR" diskXsY

验证:

mount | grep xwechat_files

看到类似下面这样的结果,就说明挂载成功了:

/dev/diskXsY on /Users/<username>/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files (apfs, local, nodev, nosuid, journaled, noowners)

5. 打开微信测试

这一步只做一件事:打开微信,看聊天记录、图片、文件是否正常。

测试时如果聊天记录、图片、文件都能正常打开,就可以继续下一步。打开微信时,macOS 会提示微信想访问外置盘,这是预期现象。因为这个目录背后已经是外置盘上的 APFS 卷了。

确认正常后,我才删除系统盘上那份几十 GB 的临时备份,系统盘空间立刻释放出来。

自动挂载

手动挂载有个问题:重启后不一定自动回到这个路径。

可以加一个 LaunchAgent,登录时自动检查并挂载,每 60 秒补偿一次。核心逻辑很简单:

#!/bin/zsh

TARGET="$HOME/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files"
VOLUME_UUID="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"

if mount | grep -q " on ${TARGET} "; then
  exit 0
fi

mkdir -p "$TARGET"
/usr/sbin/diskutil mount -mountPoint "$TARGET" "$VOLUME_UUID"

LaunchAgent 放在:

~/Library/LaunchAgents/com.example.wechatdata.mount.plist

加载:

launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/com.example.wechatdata.mount.plist

如果以后想停用:

launchctl bootout "gui/$(id -u)" ~/Library/LaunchAgents/com.example.wechatdata.mount.plist

这部分最重要的是用 Volume UUID,不要依赖 diskXsY 这种编号。磁盘编号重启后可能变,UUID 稳定得多。

这个方案的风险点

第一,外置盘必须可靠。

微信数据现在实际写在外置盘上。如果外置盘没插、没挂载,或者挂载失败,微信启动时可能会在原路径重新创建一个普通目录。这会带来混乱:新数据写到系统盘,旧数据还在 APFS 卷里。所以要么先确认挂载成功再开微信,要么用 LaunchAgent 做补偿。

第二,备份不能省。

这次软链接失败但能回滚,靠的就是原目录没有被删。微信数据不是那种“坏了再重新生成”的缓存,里面有聊天文件和历史附件。操作前至少保留一份完整备份。

第三,不建议直接照抄命令。

这类操作和本机磁盘结构强相关。比如某台机器上容器可能是 diskX,卷可能是 diskXsY,你的机器大概率不是。真正应该照抄的是流程:

确认数据目录 → 完整备份 → 新建 APFS 卷 → 复制数据 → 挂载到原目录 → 验证 → 自动挂载 → 最后清理系统盘

结论

这次最后释放了几十 GB 的系统盘空间,Xcode 和 iOS Simulator 也能继续装了。

回头看,这个方案比软链接更符合微信这种沙盒 App 的预期:路径没变,权限模型更接近普通目录,新文件也会自然写到外置盘。缺点是操作门槛更高,需要理解 APFS 卷、挂载点和 LaunchAgent。

如果只是迁移普通文件夹,软链接可能够用。但像微信这种长期增长、路径敏感、又被沙盒包着的数据目录,APFS 挂载到原目录,反而是更稳的做法。