rust版本完成

This commit is contained in:
maxf committed 2026-09-21 21:04:43 +08:00
1 parent eb3855f434
commit 8594a0167b
19 files changed
+7046 -63

No files matched your search

+142 -45
View File
@@ -1,58 +1,155 @@
# Rust 实现方案与开发指南
# Excel Keyword Search Tool — Rust 版
本文档为智能体(Agent)和开发者提供基于 Rust 语言重构 Excel 关键字搜索工具的详细设计、Cargo 配置和实施指南。
跨 Excel / Word / CSV / 文本 文件批量关键字检索工具的 Rust 实现,包含两个交付物:
## 1. 架构设计目标
- **极致的性能与最小体积**:利用 Rust 的内存安全、零成本抽象及编译优化(`opt-level = "z"`、`strip = true`),生成的独立二进制文件极小(通常在 5MB ~ 15MB 之间),运行速度达到极致。
- **全格式 Excel 解析**:基于 `calamine` 库,完美支持 `.xlsx`, `.xls`, `.xlsb`, `.ods`。
- **并行计算加速**:利用 `rayon` 库进行多核并行文件扫描与内容匹配。
- **`excel-search-rust.exe`** — 命令行搜索器(对标 Go 版 `cmd/searcher`),追求极致的单二进制体积与启动速度;
- **`excel-search-rust-desktop.exe`** — 桌面版(对标 Go 版 `cmd/desktop`):
**原生 egui/eframe 图形界面**,单 exe 直接出窗口。不沿用 Go 版"HTTP 服务 + Edge 应用窗口"
的前后端分离架构——那是受 Go 生态限制的妥协,Rust 有更好选择:
关窗即退出(无心跳判活 hack)、搜索跑后台线程 UI 全程可交互(无 30s 服务端超时截断)、
结果表原生虚拟滚动(万级命中不卡顿,无分页条)。
WebUI(独立浏览器标签页)形态仍由 Go 版提供(见 `../go/README.md`)。
## 特性
- **并发扫描**:rayon 线程池按文件并行解析,`--workers` 可配(默认 8,可用环境变量 `EXCEL_SEARCH_WORKERS` 覆盖)。
- **匹配语义与 Go 版逐字节对齐**:
- 关键字与文本均做 Unicode NFC 规范化(`cafe\u{301}` == `café`);
- 默认不区分大小写(Unicode 折叠);
- **完整单词匹配默认关闭**(模糊子串匹配);开启后要求关键字前后均为单词边界(字母/数字/组合标记/下划线之外)。
- **文件格式**:
- Excel:`.xlsx/.xlsm/.xltx/.xltm`,并借助 calamine 额外支持 `.xls/.xlsb/.ods`(Go 版不含这三种);
- Word:`.docx/.docm`(解析 `word/document.xml`,按段落定位 `Paragraph N`,表格段落一并覆盖);
- 文本:`.txt/.csv`(按行定位 `Line N`,CSV 不解析字段,整行视为纯文本)。
- **文件级缓存**:与 Go 版相同的 JSON 结构(`{"version":2,"cache":{...}}`),
按“路径 + 关键字 + ModTime + Size”判定命中;同一搜索根目录的缓存文件
(`<cache_dir>/cache_kw_<sha256(绝对路径)前16字节>.json`)可与 Go 版互换读写。
缓存目录由 `EXCEL_SEARCH_CACHE_DIR` 指定,默认运行目录下 `.cache/`。
- **健壮性**:单文件解析失败仅向 stderr 记 `warn:` 告警并跳过,不中断整次搜索;
stdout 只输出结果,`--json` 可安全被管道消费。
## 目录结构
## 2. 目录结构
```text
rust/
├── Cargo.toml
├── README.md
├── build.rs
└── src/
├── main.rs
├── error.rs
└── engine/
├── mod.rs
├── walker.rs
└── parser.rs
├── src/
│ ├── lib.rs # 库入口(engine + error)
│ ├── main.rs # CLI(clap)
│ ├── error.rs # 统一错误类型
│ ├── history.rs # 搜索历史 LRU(与 Go 桌面版同格式共用文件)
│ ├── desktop/
│ │ └── main.rs # 桌面版:原生 egui GUI(eframe)
│ └── engine/
│ ├── mod.rs # 搜索编排:并行调度 + 缓存合并 + 选项/结果类型
│ ├── matcher.rs # NFC + 大小写折叠 + 完整单词边界
│ ├── walker.rs # 目录遍历与文件类型过滤
│ ├── parser.rs # Excel(calamine) / Word(zip+quick-xml) / 文本 解析器
│ └── cache.rs # 文件级 JSON 缓存(与 Go 版 schema 兼容)
└── tests/
├── fixtures/search_sample.xlsx # 真实 xlsx 夹具(Go excelize 生成)
└── search.rs # 集成测试(与 Go scanner_test 断言语义对应)
```
## 3. 核心配置与实现规范
## 构建与测试
### 3.1 `Cargo.toml`(关键:体积与性能优化配置)
```toml
[package]
name = "excel-search-rust"
version = "1.0.0"
edition = "2021"
### 一键构建(Windows)
[dependencies]
calamine = "0.22"
rayon = "1.8"
walkdir = "2.4"
clap = { version = "4.4", features = ["derive"] }
zip = "0.6"
quick-xml = "0.31"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
双击 `rust\build.bat`,或命令行:
[profile.release]
opt-level = "z" # 针对二进制文件大小进行优化
lto = true # 链接时优化
codegen-units = 1 # 单代码生成单元,最大化优化和压缩
panic = "abort" # 移除栈展开开销
strip = true # 剥离所有调试符号
```bat
build.bat :: release 构建(默认)
build.bat debug :: debug 构建
build.bat test :: 运行全部测试
```
### 3.2 核心搜索逻辑要点 (`src/main.rs`)
- 使用 `clap` 定义命令行参数(目录、关键字)。
- 使用 `walkdir` 收集文件列表。
- 使用 `rayon` 的 `par_iter()` 并行遍历所有文件:
- 对 Excel 调用 `calamine::open_workbook_auto` 解析。
- 对文本/Word 文件进行文本匹配。
- 将匹配结果序列化为 JSON 或友好打印。
脚本自动探测工具链(优先 mise 托管的 cargo/rustup → 系统 PATH),
存在 GNU 工具链 + winlibs mingw 时自动走无 MSVC 编译路径,否则回退默认工具链并给出安装指引。
### 手动构建
```bash
cd rust
cargo test # 单元(lib 11 + 桌面 2)+ 集成(引擎端到端 10)
cargo build --release # 产物(一次构建出两个 exe;LTO 全量构建约 2-20 分钟):
# target/release/excel-search-rust.exe 命令行版 ≈1.3MB
# target/release/excel-search-rust-desktop.exe 桌面版(原生 egui GUI)≈9.6MB
```
**Windows 工具链说明**:本机若无 Visual Studio Build Tools / Windows SDK,
默认 `x86_64-pc-windows-msvc` 目标无法链接,请改用 GNU 目标(winlibs 便携版即可,免安装):
```bash
rustup target add x86_64-pc-windows-gnu
# 将 winlibs-x86_64-posix-seh-*-ucrt 解压后将 mingw64\bin 加入 PATH,然后:
cargo test --target x86_64-pc-windows-gnu
cargo build --release --target x86_64-pc-windows-gnu
# 产物:target/x86_64-pc-windows-gnu/release/ 下的两个 exe
```
## 用法
```bash
# 基本用法(默认:不区分大小写 + 模糊匹配 + 递归子目录 + 全部文件类型)
excel-search-rust --dir <目录> --keyword <关键字>
excel-search-rust <目录> <关键字> # 等价的位置参数写法
# 输出 JSON(便于脚本处理)
excel-search-rust --dir ./data --keyword 关键词 --json
# 区分大小写
excel-search-rust --dir ./data --keyword Phone --case-sensitive=true
# 完整单词匹配(默认关闭,开启后要求关键字前后均为单词边界)
excel-search-rust --dir ./data --keyword 手机 --whole-word
# 仅搜索根目录
excel-search-rust --dir ./data --keyword 关键词 --include-subdirectories=false
# 文件类型过滤:all | excel | word | csv
excel-search-rust --dir ./data --keyword 关键词 --file-type excel
# 并发 worker 数(或环境变量 EXCEL_SEARCH_WORKERS)
excel-search-rust --dir ./data --keyword 关键词 --workers 16
```
> 完整单词边界提示:汉字属于字母,因此开启完整单词后搜「手机」**不会**命中
> 「苹果手机壳」这类内部子串;默认(关闭)为模糊匹配则会命中。
## 桌面版用法
```bash
# 双击运行,直接弹出原生窗口
excel-search-rust-desktop.exe
```
窗口布局与 Go 桌面版一致:目录/关键字(含历史下拉)、四个搜索选项、结果表格
(虚拟滚动、列宽可拖拽、右键复制/打开文件)。差异是架构性的、也是更好的:
- **关窗即退出**:原生窗口生命周期与进程绑定,无心跳检测;
- **搜索不阻塞界面**:搜索在后台线程执行,进行中可继续拖动窗口/改表单;
慢目录不再被 30s 服务端超时掐断(Go 版行为);
- **中文字体**:运行时加载系统 SimHei/楷体/仿宋(epaint 不支持 .ttc 集合字体)。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
| `EXCEL_SEARCH_WORKERS` | `8` | 并发搜索线程数 |
| `EXCEL_SEARCH_CACHE_DIR` | `.cache` | 搜索缓存目录 |
搜索历史写入 `.cache/search_history.json`(与 Go 桌面版同格式,可共用同一份历史)。
## 与 Go 版的差异
| 维度 | Go 版 | Rust 版 |
|---|---|---|
| 交付形态 | searcher CLI + WebUI + 桌面版(HTTP+Edge 窗口) | CLI + 桌面版(**原生 egui**,无 WebUI) |
| Excel 格式 | xlsx/xlsm/xltx/xltm | 额外支持 xls/xlsb/ods |
| 搜索取消/超时 | context 全链路(服务端 600s 超时) | CLI:Ctrl+C 直接终止;桌面:后台线程不阻塞 UI,无超时截断 |
| 缓存 | JSON,版本 2 | 同 schema,条目可跨版本命中(已验证) |
| 日志 | slog(text/json,含请求日志中间件) | CLI stderr `warn:` 行 |
## 设计文档(历史)
原始设计指南(体积优化 profile、calamine/rayon 选型)已随实现落地,
关键决策保留在上文;`[profile.release]` 的 `opt-level="z"`、`lto`、`strip` 配置见 `Cargo.toml`。