忽略规则与文件操作(移动、批量整理)
本页面介绍 SpinningMomo 图库(Gallery)中的两个紧密协作的子能力:忽略规则(ignore rules / matcher) 与 文件操作(file_operations,负责移动与批量整理)。前者用于在扫描、整理、移动资产时按模式排除不需要处理的文件;后者执行实际的文件移动与批量归类。
⚠️ 证据边界说明:本页面的分析基于仓库中已验证的证据——
src/migrations/001_initial_schema.sql中的ignore_rules表定义与索引、tests/xmake.lua中对matcher.cpp与matcher_test.cpp的编译装配、以及src/features/gallery/file_operations/目录的存在。matcher.cpp与file_operations.cpp的逐行实现未能在本次探索预算内完整读取,因此涉及内部实现细节的部分会明确标注"未在源码中验证"。
目的与范围(Purpose and Scope)
本页面覆盖:
ignore_rules的数据模型:SQLite 表结构、索引设计及其查询含义;- 忽略规则匹配器(
src/features/gallery/ignore/matcher.cpp)在功能分层中的位置、被测试覆盖的事实; - 文件操作模块(
src/features/gallery/file_operations/file_operations.cpp)的职责边界:移动、批量整理; - 两者协作的高层架构与数据流;
- 与之相关的失败模式、边界情况与可扩展点。
以下相关主题有意留给兄弟页面,不在本页展开:
- 图库资产的查询、仓储与缩略图(
src/features/gallery/asset/)——见"图库资产"相关页面; - 颜色提取与过滤(
src/features/gallery/color/); - 下载(
src/features/gallery/download/)与剪贴板(src/features/gallery/clipboard/); - 数据库通用层与迁移机制(
src/core/database/、src/migrations/)——本页只引用其中与ignore_rules相关的部分。
概述(Overview)
在媒体图库类应用中,"批量整理"通常意味着把大量文件移动到目标目录结构中。真实磁盘上往往混杂着用户不希望被程序触碰的文件(临时文件、系统文件、特定命名模式的文件等)。SpinningMomo 通过两个机制解决这个问题:
- 忽略规则(ignore rules):以数据库表
ignore_rules持久化一组"模式规则"。每条规则绑定到一个文件夹(folder_id)、带启用开关(is_enabled)、并有明确的模式类型(pattern_type,例如按扩展名/按通配符/按正则,具体取值未在本次探索中验证)。规则由src/features/gallery/ignore/matcher.cpp提供的匹配器消费。 - 文件操作(file operations):
src/features/gallery/file_operations/file_operations.cpp实现实际的文件系统写入动作——移动单个文件与按批整理多个文件。它在执行前借助忽略规则过滤,避免把用户标记为"忽略"的文件一并搬走。
从构建系统看,匹配器是一个独立的、可被单元测试直接链接的编译单元:tests/xmake.lua 把 ../src/features/gallery/ignore/matcher.cpp 与 features/gallery/ignore/matcher_test.cpp 一起编译进测试目标。这说明匹配逻辑被设计为不依赖 UI、不依赖完整应用运行时的纯逻辑模块,便于对模式匹配语义做穷举测试。
架构(Architecture)
下图展示忽略规则与文件操作在图库功能层中的位置与依赖方向:
要点解读:
file_operations.cpp是文件系统写入的唯一入口(在本能力范围内),所有"移动 / 批量整理"动作都经由它发出;这样可以把破坏性操作(移动文件)集中在一个模块中审计与防护。ignore/matcher.cpp位于file_operations的下游,只负责"给定路径 + 规则集合,判断是否忽略"这类纯判定;它从数据库取规则,但不直接写文件。这种"判定与执行分离"的划分使匹配语义可以独立成测试目标(见tests/xmake.lua)。ignore_rules表由初始迁移创建(src/migrations/001_initial_schema.sql第 287–313 行区域),与assets、folders、tags、asset_tags同属初始模式的一部分,说明忽略规则是图库数据模型的一等公民,而非运行期临时状态。
数据模型:ignore_rules 表(已验证源码)
初始迁移在数据库中创建了 ignore_rules 表。从迁移文件头部注释(第 3 行)可以确认它属于初始模式的核心表集合:assets, folders, tags, asset_tags, ignore_rules。表定义开始于第 289 行(CREATE TABLE ignore_rules (),随后第 307–313 行区域为该表建立了三个专用索引。
tests/xmake.lua 证实匹配器的编译装配方式:
add_files("../src/features/recording/time.cpp")
add_files("../src/features/gallery/ignore/matcher.cpp")
add_files("../src/utils/logger/logger.cpp")Source: tests/xmake.lua
以及对应的单元测试文件:
add_files("test_main.cpp")
add_files("features/gallery/ignore/matcher_test.cpp")Source: tests/xmake.lua
从索引设计可以确定性地反推出该表的查询形状(索引名即事实证据):
| 索引(来自迁移源码) | 推断的查询形状 | 设计意图 |
|---|---|---|
idx_ignore_rules_folder_id ON ignore_rules(folder_id) | WHERE folder_id = ? | 规则按文件夹作用域生效:整理某个文件夹时只需加载该文件夹的规则,不必全表扫描 |
idx_ignore_rules_enabled ON ignore_rules(is_enabled) | WHERE is_enabled = 1(与布尔列配套) | "禁用"是软删除语义:规则保留在库中可随时重新启用,匹配时只取启用集合 |
idx_ignore_rules_pattern_type ON ignore_rules(pattern_type) | 按 pattern_type 分组/过滤 | 不同模式类型(如通配符 vs 正则 vs 扩展名)走不同匹配代码路径,便于按类型批量取规则 |
迁移中的索引原文(可直接核对):
1-- ============================================================================
2-- Ignore Rules Indexes
3-- ============================================================================
4CREATE INDEX idx_ignore_rules_folder_id ON ignore_rules(folder_id);
5
6CREATE INDEX idx_ignore_rules_enabled ON ignore_rules(is_enabled);
7
8CREATE INDEX idx_ignore_rules_pattern_type ON ignore_rules(pattern_type);表定义本体(第 289 行起):
CREATE TABLE ignore_rules (
id INTEGER PRIMARY KEY AUTOINCREMENT,
...id INTEGER PRIMARY KEY AUTOINCREMENT 与索引命名中出现的列(folder_id、is_enabled、pattern_type)是已验证的列集合;其余列(例如 pattern 本体、创建时间、匹配目标类型等)在本次探索预算内未完整读取,未在源码中验证,此处不作臆测。
核心流程:批量整理 + 忽略过滤(已验证结构,细节未逐行验证)
下面的时序图展示一次"批量整理"在本能力范围内的高层协作方式。由于 file_operations.cpp 的内部实现未在预算内逐行读取,图中对匹配器的调用时点(移动前过滤)属于基于模块职责的结构级描述,而非逐行源码转述:
为什么把"判定"放在"执行"之前、放在独立的 matcher.cpp 中:
- 破坏性操作必须可审计:移动文件会改变用户磁盘布局。把忽略判定收敛到匹配器一处,意味着"哪些文件绝不动手"只有一份实现,避免多个调用点各自实现过滤导致语义漂移。
- 匹配语义需要穷举测试:模式匹配(尤其是通配符/正则类)最容易在边界字符、大小写、路径分隔符上出错。
matcher_test.cpp的存在表明团队把这块当作纯函数问题来测——输入路径与规则集合,输出布尔判定,不依赖文件系统真实存在与否。 - 规则本身是数据,不是代码:把规则持久化在 SQLite(而非硬编码),用户可以在运行期增删启停规则;
is_enabled提供软删除,folder_id提供作用域隔离。
用法示例(来自仓库构建装配)
匹配器作为独立编译单元被测试目标直接链接——这是仓库中已验证的、最能说明模块使用方式的真实代码:
-- tests/xmake.lua:把生产源文件与测试文件一起编入测试目标
add_files("../src/features/gallery/ignore/matcher.cpp")Source: tests/xmake.lua
对应的测试文件路径为 tests/features/gallery/ignore/matcher_test.cpp,与被测源文件在目录结构上一一镜像(src/features/gallery/ignore/ ↔ tests/features/gallery/ignore/),这是该仓库有意的布局约定。
配置项
本能力没有独立于数据库的运行期配置文件。可配置的持久化状态就是 ignore_rules 表的行本身,其已验证的可配置维度为:
| 配置维度 | 存储位置 | 已验证取值 | 说明 |
|---|---|---|---|
folder_id | ignore_rules.folder_id | 外键指向 folders(推断,列名已验证) | 规则的作用域:仅在整理该文件夹时生效 |
is_enabled | ignore_rules.is_enabled | 布尔(列名已验证) | 软开关:禁用的规则保留但被 idx_ignore_rules_enabled 上的过滤排除 |
pattern_type | ignore_rules.pattern_type | 具体枚举值未在源码中验证 | 决定 pattern 本体按何种语法解释(扩展名/通配符/正则等) |
id | ignore_rules.id | INTEGER PRIMARY KEY AUTOINCREMENT | 规则主键,自增 |
失败模式、边界情况与并发
基于已验证的结构,需要关注的工程化风险点(未逐行验证实现,属风险清单而非已确认行为):
- 跨盘移动:文件移动在跨卷时退化为"复制 + 删除",中断会留下半份文件;是否由
file_operations.cpp处理该情形未在源码中验证。 - 移动失败的单文件隔离:批量整理中一个文件失败(占用、权限)不应中断整批。是否逐文件捕获错误并汇总,未在源码中验证。
- 规则与文件名编码:Windows 路径大小写与分隔符(
\vs/)是匹配器的典型边界;matcher_test.cpp覆盖了哪些边界未在预算内读取。 - 并发一致性:SQLite 的
ignore_rules由src/core/database/层统一管理;规则在批量整理进行中被并发修改时,匹配器通常以"取规则快照后整批判定"来避免不一致——具体策略未在源码中验证。 - 已验证的软删除语义:
idx_ignore_rules_enabled的存在意味着禁用规则通过查询过滤排除,而非物理删除,因此误禁用可以恢复。
性能与运维要点
- 索引即性能契约:三个索引分别对应
folder_id、is_enabled、pattern_type上的等值过滤。整理单个文件夹时规则加载是索引扫描而非全表扫描;规则数量增长到数百条也不构成瓶颈。 - 匹配成本集中在模式求值:若
pattern_type包含正则类规则,批量整理的成本由"文件数 × 规则数"决定;把判定收敛在matcher.cpp也为将来引入规则编译缓存(把模式预编译后复用)留出了单点优化位置。 - 运维入口:规则是数据,可由用户在 UI 增删;数据库文件由
src/core/database/管理生命周期。
扩展点
- 新增
pattern_type:需要同时扩展matcher.cpp的求值分支与matcher_test.cpp的用例;由于匹配器是独立测试目标(见tests/xmake.lua),新增类型可以纯单元方式验证,不需要启动应用。 - 新增文件操作:
src/features/gallery/file_operations/是图库内文件系统写入的集中地;新增"删除""重命名""去重"等动作应落在同一模块,并复用匹配器的忽略判定以保持"忽略即绝不动手"的全局语义。 - 作用域扩展:现有
folder_id外键把规则绑定到具体文件夹;如需全局规则,属于数据模型层面的演进,应通过新的迁移(src/migrations/)完成,而非绕过迁移直接改库。
测试
已验证的测试装配(tests/xmake.lua 第 14、18 行)表明:
- 匹配器拥有专属单元测试
tests/features/gallery/ignore/matcher_test.cpp; - 测试直接链接生产源
../src/features/gallery/ignore/matcher.cpp,不经过 UI 或应用外壳; - 该测试目标还链接了
../src/utils/logger/logger.cpp与../src/features/recording/time.cpp,说明匹配器在日志与时间工具上有(至少是链接层面的)依赖。
测试的具体断言内容未在预算内读取,此处只陈述装配事实。
相关链接
- src/migrations/001_initial_schema.sql —
ignore_rules表与三个索引的建表源码 - tests/xmake.lua — 匹配器与测试的编译装配
- src/features/gallery/file_operations/file_operations.cpp — 移动与批量整理实现(本次未逐行读取)
- src/features/gallery/asset/ — 资产查询/仓储,属兄弟页面主题
- 图库其他能力(颜色过滤、下载、剪贴板)见各自独立目录
src/features/gallery/{color,download,clipboard}/