12 KiB
Excel 关键字搜索工具(Go 版)
跨 Excel / Word / CSV / 文本 文件批量关键字检索工具,纯 Go 实现,编译为独立可执行文件,无需 Python/Pandas 运行时。支持 OOXML 格式(.xlsx/.xlsm/.xltx/.xltm、.docx/.docm)与 .csv、.txt 的并发扫描,内置文件级缓存加速重复搜索,并提供区分大小写、完整单词、子目录递归、文件类型过滤等搜索选项。
- 模块名:
excel-search(单 Go module) - Go 版本要求:≥ 1.22(开发机实测 1.27.1)
- 核心依赖:
github.com/xuri/excelize/v2 v2.8.1
一、三种交付形态
| 入口 | 路径 | 形态 | 适用场景 |
|---|---|---|---|
| 桌面版 | cmd/desktop/ |
本地 HTTP 服务 + Edge 应用模式窗口 | 日常使用,双击即用,无控制台 |
| WebUI 版 | cmd/webui/ |
本地 HTTP 服务 + 浏览器打开 | 不想用 Edge 应用窗口,用默认浏览器 |
| CLI 版 | cmd/searcher/ |
命令行工具 | 脚本化、集成到批处理/CI |
三者共享同一套搜索引擎(internal/search),行为一致。
二、目录结构与文件说明
go/
├── go.mod # 模块定义(module excel-search),声明 go 版本与直接依赖
├── go.sum # 依赖校验和锁定文件,保证构建可复现(勿手改)
├── Makefile # Linux/macOS/CI 构建脚本(build/test/vet/fmt/frontend/clean)
├── build.bat # Windows 一键构建脚本(无 make 环境使用)
├── .gitignore # 忽略 bin/、*.exe、logs/、.cache/、node_modules/ 等产物
├── .golangci.yml # golangci-lint 静态检查配置(在 CI 或本地非沙箱环境运行)
│
├── cmd/ # 可执行程序入口(每个子目录一个 main 包)
│ ├── desktop/
│ │ ├── main.go # 桌面版入口:HTTP 路由 + 历史记录 + 心跳守卫 + 优雅关闭,
│ │ │ # 前端页面以 htmlUI 字符串常量内嵌,样式经 go:embed 注入
│ │ └── style.css # 编译产物:由 frontend 生成的 Tailwind 静态样式(勿手改)
│ ├── webui/
│ │ ├── main.go # WebUI 入口:go:embed 内嵌 static/*,FileServer 托管静态页
│ │ └── static/
│ │ ├── index.html # WebUI 前端页面(引用本地 style.css,无 CDN)
│ │ └── style.css # 编译产物:由 frontend 生成的 Tailwind 静态样式(勿手改)
│ └── searcher/
│ └── main.go # CLI 入口:flag 解析(-dir/-keyword/-json/-workers/-version)
│
├── internal/ # 内部包(仅本模块可导入,不对外暴露)
│ ├── config/
│ │ └── config.go # 配置加载:从环境变量读取,带默认值(EXCEL_SEARCH_*)
│ ├── logging/
│ │ └── logging.go # 结构化日志:slog 初始化(text/json)+ request_id 生成
│ ├── model/
│ │ └── result.go # 数据模型:SearchResult 结构体(含 JSON tag)
│ └── search/
│ ├── scanner.go # 搜索引擎核心:worker pool + 全链路 context 取消 + 文件级缓存
│ ├── options.go # 搜索选项模型:SearchOptions + FileType + 扩展名分类
│ ├── matcher.go # 匹配器:Unicode NFC 规范化 + 大小写折叠 + 完整单词边界
│ ├── word.go # Word 解析:.docx/.docm 的 word/document.xml 段落提取
│ ├── scanner_test.go # 单元测试:大小写/完整单词/文件类型/递归/docx/缓存隔离
│ └── matcher_test.go # 匹配器单元测试
│
└── frontend/ # 前端构建工具链(仅在需要修改样式时使用)
├── package.json # npm 依赖声明(devDependency: tailwindcss ^3.4)
├── package-lock.json # npm 依赖锁文件(保证 npm install 可复现)
├── tailwind.config.js # Tailwind 配置:content 扫描 cmd/desktop/main.go 与 webui html
├── input.css # Tailwind 输入文件(@tailwind base/components/utilities)
└── dist/
└── style.css # 生成的静态样式(构建后复制到两个 embed 位置)
关键设计说明
-
style.css是编译产物:cmd/desktop/style.css与cmd/webui/static/style.css内容相同,均由frontend/预编译生成,并已go:embed进二进制。不要直接手工编辑,改样式走frontend/流程(见下文「前端样式编译」)。 -
搜索引擎只有一份:
internal/search/scanner.go,桌面版/WebUI/CLI 共用,不存在重复实现。 -
运行时生成目录(已 gitignore,无需提交):
logs/app.log—— 结构化日志(desktop/webui 写文件,CLI 写 stderr).cache/—— 搜索缓存与搜索历史(search_history.json)
三、编译详细步骤
1. 前置条件
| 依赖 | 版本 | 是否必需 | 说明 |
|---|---|---|---|
| Go | ≥ 1.22 | ✅ 必需 | 编译与运行 |
| Node.js + npm | 任意较新版 | ⚠️ 可选 | 仅修改样式、重新生成 CSS 时需要 |
检查环境:
go version # 需 ≥ go1.22
node --version # 可选,仅前端样式需要
2. 拉取依赖(可选)
go build 会自动下载依赖,也可手动预拉取:
cd /path/to/go
go mod download
go mod tidy # 整理 go.mod/go.sum(新增/移除依赖后执行)
3. 编译可执行文件
产物默认输出到
bin/,该目录已被 gitignore。以下命令在go/目录内执行。
方式一:Go 原生命令(逐个编译)
# 桌面版
go build -trimpath -ldflags "-s -w" -o bin/excel-search-desktop.exe ./cmd/desktop
# WebUI 版
go build -trimpath -ldflags "-s -w" -o bin/excel-search-webui.exe ./cmd/webui
# CLI 版
go build -trimpath -ldflags "-s -w" -o bin/excel-searcher.exe ./cmd/searcher
参数说明:
-trimpath:从二进制中剥离本机绝对路径,便于复现构建-ldflags "-s -w":去除符号表与调试信息,减小体积-o bin/xxx.exe:指定输出路径与文件名
方式二:Windows 一键脚本
build.bat
脚本会依次编译三个入口到 bin/,版本号可用环境变量覆盖:
set VERSION=v1.2.3
build.bat
方式三:Make(Linux / macOS / CI)
make build # 编译三个入口
make frontend # 先重建前端 CSS,再编译(完整发布流程)
make # 等价于 make frontend build
4. 注入版本号
三入口均内置 version 变量(默认 dev),通过 -ldflags 注入:
VERSION=v1.2.3
go build -trimpath \
-ldflags "-s -w -X main.version=$VERSION" \
-o bin/excel-searcher.exe ./cmd/searcher
# 验证
./bin/excel-searcher.exe -version # 输出 v1.2.3
build.bat 与 Makefile 已内置该逻辑(VERSION 环境变量,默认取 git describe 或 dev)。
5. 前端样式编译(仅修改样式时)
日常编译无需执行此步骤——
cmd/*/style.css已作为编译产物提交。仅当修改了 HTML 里的 class 或frontend/input.css时才需要重新生成。
cd frontend
npm install # 首次执行,安装 tailwindcss(生成 node_modules/,已 gitignore)
npm run build # 生成 dist/style.css(tailwindcss -c ... --minify)
# 将产物复制到两个 embed 位置
cp dist/style.css ../cmd/desktop/style.css
cp dist/style.css ../cmd/webui/static/style.css
或直接用 Make:
make frontend
6. 交叉编译
纯 Go 依赖(excelize 无 CGO),可轻松交叉编译到其他平台:
# 例:在 Windows 上编译 Linux 版
GOOS=linux GOARCH=amd64 go build -trimpath -ldflags "-s -w" \
-o bin/excel-searcher-linux-amd64 ./cmd/searcher
# 例:编译 macOS 版
GOOS=darwin GOARCH=arm64 go build -trimpath -ldflags "-s -w" \
-o bin/excel-searcher-darwin-arm64 ./cmd/searcher
注意:
go test -race依赖 CGO 工具链,交叉编译竞态检测需目标平台原生编译。
7. 测试与静态检查
# 单元测试
go test ./...
# 竞态检测(需 gcc/CGO,建议 Linux CI 或安装 MinGW)
go test -race ./...
# 静态检查
go vet ./...
gofmt -l . # 输出为空表示格式规范
# 更全面的 lint(需先安装 golangci-lint)
golangci-lint run ./...
四、运行方式
桌面版(excel-search-desktop.exe)
双击运行,自动启动本地服务并用 Edge 应用模式窗口打开。窗口关闭后,后端检测到心跳超时(30s)自动优雅退出。
WebUI 版(excel-search-webui.exe)
双击运行,控制台打印访问地址并自动打开默认浏览器。
CLI 版(excel-searcher.exe)
# 基本用法(默认:不区分大小写 + 模糊匹配(关闭完整单词)+ 递归子目录 + 全部文件类型)
excel-searcher -dir <目录> -keyword <关键字>
# 输出 JSON(便于脚本处理)
excel-searcher -dir ./data -keyword 关键词 -json
# 区分大小写(默认不区分)
excel-searcher -dir ./data -keyword Phone -case-sensitive
# 完整单词匹配(默认关闭,开启后要求关键字前后均为单词边界)
excel-searcher -dir ./data -keyword 手机 -whole-word
# 仅搜索根目录,不递归子目录(默认递归)
excel-searcher -dir ./data -keyword 关键词 -include-subdirectories=false
# 按文件类型过滤:all | excel | word | csv
excel-searcher -dir ./data -keyword 关键词 -file-type excel
# 指定并发 worker 数
excel-searcher -dir ./data -keyword 关键词 -workers 16
# 查看版本
excel-searcher -version
搜索选项说明
| 选项 | 默认值 | 含义 |
|---|---|---|
区分大小写 -case-sensitive |
不勾选 | 勾选后按大小写精确匹配;不勾选按 Unicode 大小写折叠匹配 |
完整单词 -whole-word |
不勾选 | 勾选后要求关键字前后均为单词边界(非字母/数字/下划线);不勾选为模糊子串匹配 |
包含子目录 -include-subdirectories |
勾选 | 勾选后递归扫描子目录;不勾选仅扫描根目录 |
文件类型 -file-type |
all | all(全部支持格式)/ excel / word / csv |
完整单词边界说明:边界字符为字母、数字、Unicode 组合标记与下划线。中文/日文汉字属于字母,默认不勾选完整单词(模糊子串匹配),搜索「手机」会匹配「苹果手机壳」这类内部子串;需要精确按词匹配时勾选完整单词即可。WebUI/桌面版的 HTTP 请求中,这些选项通过
options对象传递(字段名与上文相同,布尔字段可显式传false)。
五、配置项(环境变量)
| 环境变量 | 默认值 | 生效入口 | 说明 |
|---|---|---|---|
EXCEL_SEARCH_HOST |
127.0.0.1 |
desktop/webui | HTTP 监听地址 |
EXCEL_SEARCH_PORT |
0(随机) |
desktop/webui | HTTP 端口 |
EXCEL_SEARCH_WORKERS |
8 |
desktop/webui/searcher | 并发 worker 数(CLI 可用 -workers 覆盖) |
EXCEL_SEARCH_TIMEOUT_SECONDS |
600 |
desktop/webui | 单次搜索超时 |
EXCEL_SEARCH_LOG_DIR |
logs |
desktop/webui | 日志目录 |
EXCEL_SEARCH_LOG_FORMAT |
text |
全部 | 日志格式:text 或 json |
EXCEL_SEARCH_CACHE_DIR |
.cache |
全部 | 搜索缓存目录 |
示例(Windows PowerShell):
$env:EXCEL_SEARCH_LOG_FORMAT = "json"
$env:EXCEL_SEARCH_WORKERS = "16"
.\bin\excel-search-desktop.exe
六、常见问题
Q:桌面版窗口一闪而过 / 白屏?
先确认 .exe 与源码同目录运行时能否生成 logs/app.log,查看日志定位。白屏多与前端样式未编译有关——确认 cmd/desktop/style.css 存在(或重新执行 make frontend)。
Q:CLI 报 Search failed?
检查 -dir 路径是否存在、是否有权限;用 -json 观察输出。搜索超时请缩小目录范围或调低并发。
Q:如何彻底清理?
make clean # 删除 bin/、.cache/、logs/
rm -rf frontend/node_modules # 删除前端依赖