从零实现的数据恢复工具(NTFS · FAT · exFAT)
通过 Windows 原始磁盘读取接口解析 NTFS / FAT / exFAT 文件系统、重建目录树,支持扫描、搜索与选择性恢复已删除或误格式化后仍存留的文件。
fsrec 是一款面向 Windows 的数据恢复工具,支持 NTFS / FAT12 / FAT16 / FAT32 / exFAT 文件系统。
它不依赖任何第三方恢复引擎,而是直接从文件系统底层数据结构出发——解析引导扇区(BPB)、NTFS
主文件表($MFT)、FAT 目录项与数据运行(Data Run),在内存中重建完整的目录树。你可以像浏览
普通文件一样浏览那些已被删除、被清空回收站,甚至在分区被误格式化后仍残留在磁盘上的文件,
并按原目录结构把它们恢复到另一块磁盘。
| 维度 | 说明 |
|---|---|
| 语言 / 运行时 | C++17(MSVC,Windows x64) |
| 网络层 | libuvcpp(HTTP / WebSocket / 静态文件,仅引用) |
| JSON | nlohmann/json(单头文件,已内置) |
| 前端 | 单文件原生 HTML/CSS/JS(frontend/dist/index.html,零构建步骤) |
- 🔍 磁盘枚举 — 列出物理磁盘与盘符,自动识别并锁定系统盘(磁盘 0,禁止选择)
- 🧭 引导扇区解析 — 读取 BPB:字节/扇区、扇区/簇、
$MFT起始 LCN、记录大小等 - 📚
$MFT解析 — 遍历文件记录,USA 修复,提取$STANDARD_INFORMATION/$FILE_NAME/$DATA - 🧩 数据运行解析 — resident / non-resident 属性,含稀疏簇处理
- 🌲 目录树重建 — 依据父引用与文件名(含
$MFT编号兜底)构建完整树 - 🗂️ 分区级扫描 —
raw_scan_all遍历整盘,定位每个分区(NTFS 经$MFT搜索,FAT/exFAT 经 MBR 分区表)并分别缓存;支持 深度扫描(整盘逐区搜$MFT,能发现被格式化/覆盖后残留的 NTFS)与 快速扫描(按分区表定位、跳过整盘搜索)两种模式 - 💾 多文件系统 — 同时解析 FAT12/16/32 与 exFAT(BPB / 目录项 / FAT 链 / exFAT 文件+流+名称项)
- 🔎 搜索过滤 — 前端按名称 / 类型快速筛选
- ♻️ 选择性恢复 — 保留原目录结构写入输出目录,同名文件自动改名,支持暂停 / 继续 / 停止
- 📡 实时进度 — WebSocket 推送总体进度 + 当前文件 + 每文件字节进度;刷新页面后自动恢复进行中的任务
- 📊 磁盘监控 — 实时读取速度(全局 + 单盘)、点击磁盘展开任务管理器风格动态折线图、磁盘热插拔自动刷新并提示任务中断
- 🛡️ 安全与空间 — 源盘锁定(目录选择器禁用源盘)、空间预估与不足警告
从 Releases 下载 fsrec_Setup_1.0.18.exe,
双击安装(全中文向导)。安装完成后双击桌面 / 开始菜单的 fsrec 图标:
- 自动触发 UAC 提权(
requireAdministrator清单) - 服务在后台启动,并自动打开浏览器访问 Web UI
- 选择源磁盘 → 扫描 → 勾选文件 → 恢复到另一块磁盘
前置条件:Windows、Visual Studio 2022(MSVC,需匹配预编译的 libuvcpp 二进制)、CMake ≥ 3.20。
git clone https://github.com/Antruly/fsrec.git
cd fsrec
cmake -S . -B build -A x64
cmake --build build --config Release产物 build\Release\recovery_server.exe,运行时依赖同目录下的 uvcpp.dll、uv.dll、
llhttp.dll、libssl-3-x64.dll、libcrypto-3-x64.dll。
📌 libuvcpp 为独立仓库:Antruly/libuvcpp,fsrec 仅引用其 构建产物,路径在
CMakeLists.txt的LIBUVCPP_ROOT。
recovery_server.exe # 监听 127.0.0.1:8080(仅本机),自动打开浏览器
recovery_server.exe --port 8090 # 指定端口
recovery_server.exe --host 0.0.0.0 # 监听所有网卡(局域网内其他设备可访问)
recovery_server.exe --no-browser # 不自动打开浏览器🔒 安全默认值:服务默认只监听
127.0.0.1(仅本机可访问)。只有当你明确需要让 局域网内其他设备访问网页界面时,才用--host 0.0.0.0,或在安装向导里把「监听地址」 改成0.0.0.0/ 具体网卡 IP。
健康检查:
curl http://localhost:8080/ping
# → {"status":"ok","name":"fsrec","version":"1.0.18"}flowchart LR
A[💻 Web UI] <-->|HTTP / WebSocket| B[libuvcpp 服务器]
B --> C[Scanner 后台扫描]
B --> D[Restorer 后台恢复]
C --> E[NTFS 引导扇区解析]
E --> F[$MFT 解析]
F --> G[数据运行解析]
G --> H[目录树重建]
H --> I[扫描结果缓存]
D --> J[输出目录]
C & D -.实时进度.-> A
- 读取:以
CreateFile(\\.\PhysicalDriveN, GENERIC_READ)只读打开源盘,绝不在源盘写入。 - 定位:解析引导扇区 BPB,找到
$MFT起始位置与记录大小。 - 解析:遍历
$MFT文件记录,修复 USA,提取属性与数据运行,重建目录树。 - 恢复:按用户勾选的路径,将文件内容(含已删除但仍残留的数据簇)原样写入另一块磁盘。
fsrec/
├── CMakeLists.txt
├── src/
│ ├── main.cpp # 入口:管理员检测 + 参数解析 + 启动服务 + 自动开浏览器
│ ├── include/ # types.h / util.h / util.cpp / version.h
│ ├── ntfs/ # disk_reader / boot_parser / data_run / mft_parser / tree_builder
│ ├── fat/ # fat.cpp / fat.h — FAT12/16/32 + exFAT 解析(BPB / 目录 / FAT 链)
│ ├── recovery/ # scanner(后台扫描)/ restorer(后台恢复)
│ └── http/server.* # 路由 + WebSocket 推送中心
├── resources/
│ ├── icon.png # 图标母版(make_icon.ps1 生成 fsrec.ico)
│ ├── fsrec.ico # 多尺寸应用图标
│ └── fsrec.rc # 版本信息 + 图标资源(提权清单由 /MANIFESTUAC 链接器内嵌)
├── frontend/
│ └── dist/index.html # 线上前端(单文件;frontend/src 为废弃的 Vue 残留)
├── docs/
│ ├── 使用说明.md # 用户手册(操作流程 + 注意事项 + FAQ)
│ └── 免责声明.md
├── packaging/
│ ├── fsrec.iss # Inno Setup 安装脚本(全中文)
│ └── languages/ChineseSimplified.isl
├── scripts/
│ ├── make_icon.ps1 # icon.png → fsrec.ico
│ └── build_release.ps1 # 一键构建 + 打包安装程序
├── start.bat / stop.bat # 启动 / 停止脚本
└── LICENSE / README.md
前置条件:已安装 Inno Setup 6;脚本会首次自动下载简体中文语言文件。
powershell -ExecutionPolicy Bypass -File scripts\build_release.ps1产物输出到 release\fsrec_Setup_1.0.18.exe(全中文安装向导,安装后生成开始菜单 / 桌面快捷方式,
双击 exe 自动提权并打开浏览器)。
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /ping |
健康检查(含 name / version) |
| GET | /api/physical_disks |
物理磁盘列表(disk_number / model / size) |
| POST | /api/raw_scan_all |
{disk_number, deep} 遍历整盘定位所有分区(deep=true 深度整盘搜 $MFT)→ 各分区独立 task |
| GET | /api/scans |
已完成的扫描(含持久化缓存) |
| GET | /api/active |
进行中的扫描 / 恢复任务(刷新页面后恢复状态用) |
| GET | /api/scan/{id}/status |
扫描进度 |
| GET | /api/scan/{id}/results |
目录树(根节点 /) |
| POST | /api/scan/{id}/pause|resume|stop |
暂停 / 继续 / 停止扫描 |
| POST | /api/recover |
{task_id, selected_paths[], output_dir} → {job_id} |
| GET | /api/recover/{id}/status |
恢复进度(含 current_file / current_bytes / current_size) |
| POST | /api/recover/{id}/pause|resume|stop |
暂停 / 继续 / 停止 |
| GET | /api/fs/drives |
盘符 + physical_disks[] 映射 + 可用空间 |
| GET | /api/fs/list?path= |
目录列表(选择器用) |
| POST | /api/fs/mkdir |
{path, name} 新建目录 |
| GET | /api/fs/space?path= |
目标卷 free / total |
| WS | /ws |
WebSocket 扫描 / 恢复进度实时推送 |
- 源盘通过
CreateFile(GENERIC_READ)只读打开,绝不写入源盘。 - 恢复输出目录后端会校验并拒绝与源盘 / 系统盘相同的磁盘。
- 已删除文件的数据区可能已被覆写,不可恢复项会标注。
- 同名文件自动追加
_1、_2… 后缀,不覆盖。 - 请勿在存有重要数据的生产机上随意测试;详见
docs/使用说明.md与docs/免责声明.md。
- Antruly/libuvcpp — HTTP / WebSocket / 静态文件服务器框架
- nlohmann/json — 现代 C++ JSON 库
MIT © 2026 Antruly