可以把这个现象拆成 两套 Undo 机制叠加 来理解:VS Code 自己维护文件操作的撤销记录,同时 Windows Explorer/Windows Shell 对“移入回收站”这类文件操作也有自己的撤销能力。
1. VS Code 删除文件时,并不只是简单调用 DeleteFile
当你在 VS Code Explorer 中删除文件,并选择“Move to Recycle Bin”时,大致流程是:
VS Code Explorer
│
│ Delete
▼
VS Code 文件操作层
│
├── 记录一次 Workspace File Operation
│ delete: xxx/test.txt
│
└── 调用系统 Trash / Recycle Bin
│
▼
Windows Shell
│
▼
Recycle Bin
VS Code 自己知道:
“刚才用户从
D:\project\test.txt删除了一个文件。”
因此,当你随后在 VS Code 文件树中执行 Undo(Ctrl+Z)时,它可以执行一个与删除对应的恢复操作。
这就是为什么 VS Code 自己能够 Undo 文件删除。
需要注意的是,这和编辑器文本的 Ctrl+Z 不是完全同一个层面的东西。VS Code 有专门针对文件创建、删除、移动、重命名等资源操作的 Undo/Redo 管理。
2. 为什么 Explorer 也能撤销这次删除?
这里更有意思。
关键点不是 VS Code 把自己的 Undo Stack 分享给了 Explorer,而是:
VS Code 删除文件时使用了 Windows 提供的 Shell/Recycle Bin 文件操作机制。
Windows Shell 本身知道:
D:\project\test.txt
↓
Recycle Bin
这次操作属于 Windows Shell 可以追踪/恢复的文件操作。
所以你打开 Windows Explorer,在对应目录执行:
Ctrl + Z
Explorer 可以出现类似:
Undo Delete
然后 Windows 从回收站恢复:
Recycle Bin
↓
D:\project\test.txt
因此实际上存在两个不同层次:
| 层次 | 谁维护 | 用途 |
|---|---|---|
| VS Code Undo | VS Code | 撤销文件创建、删除、移动、重命名等 |
| Windows Shell Undo | Windows Shell / Explorer | 撤销 Delete / Move / Rename 等 Shell 文件操作 |
它们不是共享同一个 Undo Stack。
3. VS Code 在 Windows 上是怎么把文件送进回收站的?
现代 VS Code 的文件系统实现经过多次演进,所以具体内部调用链要以对应版本源码为准;但从架构上看,它不是把文件内容复制到某个 VS Code 临时目录,然后让 Explorer 知道这件事。
核心操作是:
VS Code
│
│ trash(file)
▼
Electron / Node / native integration
│
▼
Windows Shell recycle-bin mechanism
│
▼
$Recycle.Bin
Windows 的回收站也不只是:
MoveFile("a.txt", "C:\\$Recycle.Bin\\xxx")
这么简单。
Windows 会保存恢复文件所需要的元数据,例如原始路径等。现代 Windows 的 $Recycle.Bin 中通常能看到成对的数据,例如:
$Rxxxxxx.txt
$Ixxxxxx.txt
大致可以理解为:
$Rxxxxxx.txt
实际被删除的数据
$Ixxxxxx.txt
原文件信息
├── 原始路径
├── 文件大小
└── 删除时间
所以系统知道:
$Recycle.Bin\$RABCDEF.txt
│
│ restore
▼
D:\project\src\test.txt
应该恢复到哪里。
4. Explorer 为什么知道“刚才 VS Code 删除了这个文件”?
这里需要区分两个概念。
Explorer 并不是读取:
VS Code Undo Stack
而是依赖 Windows Shell 的文件操作/回收站机制和 Shell 状态。
也就是说,类似:
VS Code
└─ Delete foo.cpp
│
▼
Windows Shell operation
│
├─ Recycle Bin metadata
└─ Shell operation state
Explorer
│
└─ Undo Delete
│
▼
Windows Shell restore
因此这个 Undo 能够跨应用表现出来。
这也是最值得注意的一点:
“Explorer 能撤销 VS Code 的删除”主要是 Windows Shell 能力,而不是 VS Code 实现了一个跨进程 Undo 协议。
5. 为什么直接 DeleteFileW() 往往没有这种效果?
假设自己写 C++:
DeleteFileW(L"D:\\project\\test.txt");
这基本就是:
Application
│
▼
NTFS 删除文件
没有:
Recycle Bin
Shell File Operation
Undo information
所以 Explorer 通常无法:
Ctrl+Z → Undo Delete
因为文件本身已经真正删除了。
如果要实现类似 Explorer/VS Code 的体验,在 Windows 原生程序中,更接近的思路是使用 Windows Shell 的文件操作接口,而不是裸 DeleteFileW。
现代 Windows 主要可以研究 IFileOperation;老代码里经常会看到 SHFileOperation。例如 IFileOperation 可以表达:
DeleteItem
MoveItem
CopyItem
RenameItem
并让 Shell 参与整个文件操作。
6. 一个很容易混淆的地方
可以做一个实验:
VS Code:
delete a.txt
↓
Windows Explorer:
Ctrl+Z
↓
a.txt 恢复
此时 VS Code 的文件监控器会收到文件系统变化:
FileWatcher
│
▼
a.txt created
所以 VS Code Explorer 又会看到 a.txt。
这里不是:
Explorer
↓
通知 VS Code:
“我执行了你的 Undo”
而更像:
Explorer
↓
Windows 恢复 a.txt
↓
Filesystem change
↓
VS Code FileWatcher
↓
刷新 Explorer Tree
这与 VS Code 自己执行 Undo 是两条不同的路径。
7. 整体架构可以理解成这样
┌──────────────────────┐
│ VS Code │
│ │
│ Explorer │
│ File Operation Undo │
└──────────┬───────────┘
│
delete / trash
│
▼
┌───────────────────────┐
│ Windows Shell / OS │
│ File Operation │
└──────────┬────────────┘
│
▼
┌──────────────┐
│ Recycle Bin │
│ │
│ $R... data │
│ $I... meta │
└──────────────┘
▲
│
Explorer Ctrl+Z
│
┌──────────┴────────────┐
│ Windows Explorer │
└───────────────────────┘
因此你观察到的现象实际上说明了两个事实:
VS Code Ctrl+Z 能恢复
VS Code 自己记录文件操作
+
利用系统 Trash/Recycle Bin 恢复
而 Explorer Ctrl+Z 也能恢复
删除本身进入了 Windows Shell / Recycle Bin 的文件操作体系
二者最终都作用于同一个真实文件系统,因此任何一方恢复文件,另一方都能通过文件监控看到变化。
如果你是想在自己的 C#/C++ 文件树组件里实现与 VS Code 完全类似的“删除 → VS Code/Explorer 都可以 Ctrl+Z”行为,重点应该继续研究 Windows 的 IFileOperation、Shell Undo 与 Explorer 的 undo state。这部分比单纯调用回收站 API 更关键。
