删掉的照片去哪了?512 个磁盘块实测 JPEG 残留与覆盖
删掉一张照片,数据并没有立刻消失。
我拿一块 512 KB 的模拟磁盘做实测:删掉一张 160 KB 的 JPEG,163,840 字节一个不少,删前删后的 MD5 完全相同。

再删掉全部 5 个文件,461,824 字节仍然能完整恢复,恢复率 100%。
可只要往这些块里写新数据,结果立刻变差。覆盖 25% 剩 4 个文件,覆盖 75% 只剩 1 个,覆盖 100% 归零。
结论先放这儿:删除只是把目录项标成 0xE5,真正的删除是覆盖。
为什么值得看
几乎每个人都删过照片,也都听过“删了还能恢复”。
但多数人以为恢复靠运气,或者以为清空回收站就彻底没了。
这块实验室把中间过程拆开了:磁盘被切成 512 个块,每块 1024 字节,删除、扫描、覆盖都能看见。
看懂之后,你会知道两件事。
第一,误删之后最重要的动作是停止写入,而不是继续拍新照片。
第二,卖二手硬盘前只点“删除”不够,得让新数据真正覆盖旧块。
准备环境:进入码道 Web
浏览器打开码道 Web 版:https://devcloud.cn-north-4.huaweicloud.com/chat?source=dmzntgwlb&sourcead=dmzntgwlb1&invitecode=INV-IXhxk5bwWx_qKSP1FcgSuiOEf6ruDXtjvLFiCH9nMs5dZGLapaSSylwt-cKRj5LoT3MlxikWxy8VhqplfvtQjefQOq31Tbp3R3wYP3K535Cn4XTaUzqqExKPYTWvvw4LijV14IS1torXdTGp7oyXb6SR5VxgYTg50jM,登录后直接在对话窗口输入需求。
码道有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。本文用 WebUI 版演示。
我让码道做了什么
需求写得很具体,核心是四件事。
磁盘固定 512 块,每块 1024 字节,用 FAT 链表分配。
预置 5 个文件:3 张 JPEG、1 个文本、1 段 MP4,内容用固定种子生成,刷新后结果不变。
删除只改目录项状态并释放块链,绝不清零数据块。
恢复走两条路:先按目录项找,再按 JPEG 和 MP4 的文件头签名扫描空闲块。
码道最后交付了一个单文件 index.html,749 行,没有外部依赖。
页面左边是文件列表和操作按钮,右边是磁盘地图,下面是十六进制查看器和自检面板。
磁盘地图按文件着色,鼠标悬停能看到块号和前 16 字节。删除后对应区域变灰,但灰色只是“可写”,不是“已清空”。

验证一:16 项断言全部通过
页面自带自检按钮,点一次会逐条跑 16 项断言。
结果 16/16 通过,关键几条如下。
| 断言 | 实测值 |
|---|---|
| 删除后数据块非零字节不变 | 163232 → 163232 |
| 删除前后原始 MD5 一致 | 88c8796d3f909983d5d5b3d2c91a7b42 |
| 扫描能找到 3 个 JPEG | 目录项 3 条,签名扫描 3 条 |
| 恢复文件与原文件逐字节一致 | 163840 字节全等 |
| 覆盖 100% 后签名扫描 | 命中 0 |
| 磁盘满时报错 | 需要 100 块,空闲 45 块 |
| 文件名重复报错 | photo-a.jpg 已存在 |
复现方式不复杂。本地起一个静态服务,打开页面点“运行自检”即可。
python -m http.server 8000
自检不是万能证据。它由页面自己执行,断言写错了也会“全过”。
所以我另外做了一次外部复算。
验证二:把 512 KB 磁盘导出给 Python 算
我把删除后的整块磁盘导出成 base64,拼回 512 KB 二进制,再用 Python 独立计算。
三项结果和页面完全对得上。
photo-a 的 160 个块拼起来,MD5 是 88c8796d3f909983d5d5b3d2c91a7b42。
非零字节数是 163232,占 163840 的 99.6%。
整盘非零字节 460026,块首签名 4 个,其中 JPEG 3 个、MP4 1 个。
这一步比“页面说全过”更有说服力,因为它不依赖页面里的 MD5 实现。

踩坑:签名扫描的结果一直是 0
第一版的恢复列表只有目录项结果,签名扫描永远 0 条。
原因很直接:扫描循环跳过了所有“已被目录项命中的起始块”。
删除后的文件起始块本来就在目录项里,于是签名扫描一条都碰不到。
这等于把第二条恢复路径写死了,页面上“签名雕刻”四个字成了摆设。
我删掉那行跳过逻辑,让两条路径都跑,再按 MD5 去重,避免同一个文件算两次。
修完后数字才开始变化:全删状态 4 条签名命中,覆盖 25% 剩 3 条,50% 剩 2 条,75% 剩 1 条,100% 归零。
这个修复也说明一件事:AI 交付的“自检全绿”不等于逻辑正确,断言本身可能绕开了缺陷。
结果:覆盖越多,能救回的越少
在同一份“已删除 5 个文件”的状态上,依次覆盖 25%、50%、75%,每次重扫。
| 覆盖比例 | 实际覆盖块数 | 可恢复文件 | 可恢复字节 | 恢复率 | 签名命中 |
|---|---|---|---|---|---|
| 0% | 0 | 5 | 461,824 B | 100% | 4 |
| 25% | 113 | 4 | 297,984 B | 64.5% | 3 |
| 50% | 226 | 3 | 199,680 B | 43.2% | 2 |
| 75% | 338 | 1 | 65,536 B | 14.2% | 1 |
| 100% | 451 | 0 | 0 B | 0% | 0 |
覆盖顺序按块号从小到大,所以先坏的是 photo-a,最后剩下的是排在末尾的 photo-c。
现实里的文件系统不会这么整齐,但这个单调关系成立:写入越多,残留越少。

边界:这个实验室不模拟什么
它是教学模型,不是数据恢复软件。
目录项存在页面的数组里,没有真的写进 0-15 号块。十六进制查看器看块 0,全是 0。
文件都是连续分配的。签名扫描从文件头一直读到第一个 FF D9,遇到碎片文件会读错。
它模拟的是机械硬盘语义。真实的 SSD 删除后可能触发 TRIM,块会被主控清零,恢复窗口更短。
它没有 NTFS 的 MFT、ext4 的 inode、日志和事务,也没有权限与加密。
最重要的一条:真误删了,先断电或停止写入,别在原盘上装恢复软件。
使用码道体会
这次体验最明显的是“界面完成度”,不是“逻辑正确率”。
磁盘地图、色块图例、十六进制视图、覆盖表格,一次就给全了,排版也没散。
但恢复路径被跳过这种问题,页面自己不会喊,需要人把数据流走一遍。
我的做法是先看断言覆盖了什么,再看它没覆盖什么。签名扫描恒为 0,就是断言没覆盖到的地方。
另外,自检项不是越多越好。原来自检里有一条“覆盖 100% 后签名扫描 = 0”,在修复前是恒真断言,等于没测。
修复后它才有意义,因为 25% 到 75% 会先出现非零值。
下一步
如果你只想记一句话:删除不是擦除,覆盖才是。
想自己试,可以在码道里复刻这个需求,或者把块数改小到 64 块,先跑通再加大。
下一步我准备补两个场景:目录项被覆盖后的纯签名恢复,以及碎片文件的恢复失败对照。

浙公网安备 33010602011771号