WorkBuddy 数据目录 Junction 迁移
适用场景
- 把
C:\Users\<用户>\.workbuddy搬到 D/F 盘释放 C 盘空间,且不动任何应用配置 - 迁移任意"被应用实时占用 + 大量小文件"的核心数据目录到其他卷
- 目标:原路径继续可用(透明),数据实际落在新盘
核心原理
Windows 目录联接(junction, mklink /J Link Target):
- 不需要管理员权限(区别于 symlink)
- 可跨卷(C → F)
- 对应用完全透明:所有 原路径\... 自动解析到 目标路径\...
- 应用配置、脚本里的绝对路径、运行时二进制路径全部无需修改
安全流程(务必按顺序,不可跳步)
第 0 步:侦察(只读,安全)
先确认迁移可行,再动手。检查项:
- 源目录大小与顶层结构(du -sh / Get-ChildItem)
- 目标盘剩余空间(需 ≥ 源目录大小 + 10% 余量)
- 目标路径是否已存在(若已存在,确认是空目录或可覆盖,否则换子目录方案,如 F:\WorkBuddy\.workbuddy 而非直接 F:\WorkBuddy)
- 源目录是否正被应用占用(运行中应用 = 改名会失败的最大风险)
若源是正在运行的 WorkBuddy 自身数据目录,当前会话本身就是 junction 工作的最强证据——身份文件经原路径注入并成功加载,即说明文件系统层已通。
第 1 步:robocopy 全量复制
用 robocopy 把源目录完整复制到目标路径。关键参数:
robocopy $src $dst /E /COPY:DAT /DCOPY:DAT /R:1 /W:1 /XJ /NFL /NDL /NP /LOG:"$src\robocopy-migration.log"
参数解释:
- /E 含空子目录;/COPY:DAT 数据+属性+时间戳;/DCOPY:DAT 目录时间戳
- /R:1 /W:1 失败重试 1 次等待 1 秒(避免被锁定文件长时间卡住)
- /XJ 必加:排除源里的 junction/symlink,否则会递归复制造成循环或嵌套
- /NFL /NDL /NP 精简输出;/LOG 写日志便于事后核查
退出码 0–7 为成功(0=无变化,1=有复制,<8 都算正常);≥8 才有错误,需查日志定位(通常是个别被独占锁定的运行时文件,如浏览器 Cookies、SQLite WAL,这些在 junction 建立后应用会重建,非核心数据损失)。
2.3GB / 大量小文件约需 1–8 分钟,建议后台运行。
第 2 步:验证复制完整性
- 对比源与目标的顶层目录/文件数量与大小
- 抽查关键文件(身份文件、配置、脚本)大小一致
- 检查目标下无嵌套同名子目录(若 robocopy 在 junction 建立后才跑,会因 src=junction 解析到 dst 而自复制,产生
dst\.workbuddy\.workbuddy嵌套——这是最隐蔽的故障,必须排查)
第 3 步:停止占用进程 + 原目录改名备份
这是整个流程唯一的硬阻断点:源目录正被运行中应用占用时,Rename-Item 会报 Access Denied。
处理:
1. 完全退出占用应用(WorkBuddy 需退出主窗口 + 系统托盘图标,确认进程列表无残留)
2. 将原目录改名为 <原名>_old 作为备份(不要直接删除,留回退余地)
powershell
Rename-Item "C:\Users\<用户>\.workbuddy" ".workbuddy_old"
3. 若改名仍失败,用资源管理器或 handle.exe/Get-Process 定位占用句柄,或重启系统后再试
第 4 步:创建 junction
原路径必须已不存在(已被改名),否则 mklink 报"已存在"。
# junction 不需管理员权限
cmd /c mklink /J "C:\Users\<用户>\.workbuddy" "F:\WorkBuddy\.workbuddy"
注意:PowerShell 工具中 cmd.exe 被禁用时,改用 New-Item -ItemType Junction -Path <link> -Target <target>。
第 5 步:双向验证 + 冒烟测试
验证 junction 对应用透明,数据可正常读写:
- Get-Item <原路径> 显示 LinkType: Junction, Target: <目标>
- 经原路径读关键文件 + 经目标路径读同一文件,大小一致
- 冒烟测试矩阵(按目标目录的实际内容选):
- skills / 配置 / 脚本目录可列出
- 运行时二进制(如 python.exe)可执行
- 自动化任务库(SQLite)可读
- 端到端触发一次代表性脚本(如 smtp 邮件实发),确认链路无损
第 6 步:清理备份(观察 1–2 天后)
确认应用重启后一切稳定(自动化任务正常触发、邮件正常发、skills 正常加载),再删除备份释放空间:
# 必须先退出占用应用,再删备份
Remove-Item "C:\Users\<用户>\.workbuddy_old" -Recurse -Force
关键陷阱(详见 references/troubleshooting.md)
- 源被运行中应用占用 → 改名失败:必须退出应用,无绕过
- robocopy 不加 /XJ → 复制源里的 junction 造成循环
- junction 建后再跑 robocopy → src 解析到 dst 自复制,产生嵌套:复制必须在建 junction 前完成
- 目标路径已存在非空目录 → 直接 junction 会混入旧数据:用子目录方案隔离
- PowerShell 工具禁用 cmd.exe:junction 创建改用
New-Item -ItemType Junction - 含中文路径的 .ps1 脚本编码乱码:脚本内消息用英文,路径用参数传入,避免硬编码非 ASCII
一键脚本
scripts/migrate_workbuddy_junction.ps1:参数化的完整迁移脚本(侦察→复制→验证→改名→建联接→双向验证),英文消息 + 参数化路径,编码安全。适用于源目录未被占用或已退出应用后的一键执行。
回滚
junction 建立后若发现异常:
1. 删除 junction(Remove-Item <原路径>,对 junction 本身操作不影响目标数据)
2. 把 <原名>_old 改回原名
3. 数据回到迁移前状态,无损失