{"solution_id":"repairing-persisted-path-alias-drift","schema_version":1,"locale":"zh-cn","slug":"repairing-persisted-path-alias-drift","title":"文件明明存在，归档却报找不到","description":"一次受保护且可回滚的修复：本地任务存储仍保存旧物理路径，应用归档却已经按新的逻辑主目录工作。","date_published":"2026-08-21","date_modified":"2026-08-21","tags":["windows","sqlite","路径解析","故障排查","数据完整性"],"categories":["DevOps"],"structure_source":"legacy-derived","completeness":"partial","canonical_url":"https://fichil.com/zh-cn/blog/repairing-persisted-path-alias-drift/","alternate_locale_url":"https://fichil.com/blog/repairing-persisted-path-alias-drift/","problem":"界面报错可能来自源文件丢失、权限不足、数据库损坏或路径过期。任何修复之前，先用只读检查缩小范围： 目标记录仍在状态库中，归档状态没有改变； 会话文件唯一存在，并且没有活动写入者； 数据库快速一致性检查通过； 物理路径与逻辑路径解析出的文件大小和 SHA 256 一致； 已使用逻辑路径的其他记录能够正常归档； 应用日志把错误定位在归档事务内部。 这些证据排除了重置整个应用的必要性，也给出了安全边界：先修复路径元数据，再让应用自己完成文件移动和状态切换。","symptoms":["界面报错可能来自源文件丢失、权限不足、数据库损坏或路径过期。任何修复之前，先用只读检查缩小范围：","目标记录仍在状态库中，归档状态没有改变；","会话文件唯一存在，并且没有活动写入者；","数据库快速一致性检查通过；","物理路径与逻辑路径解析出的文件大小和 SHA 256 一致；","已使用逻辑路径的其他记录能够正常归档；","应用日志把错误定位在归档事务内部。","这些证据排除了重置整个应用的必要性，也给出了安全边界：先修复路径元数据，再让应用自己完成文件移动和状态切换。"],"evidence":["界面报错可能来自源文件丢失、权限不足、数据库损坏或路径过期。任何修复之前，先用只读检查缩小范围：","目标记录仍在状态库中，归档状态没有改变；","会话文件唯一存在，并且没有活动写入者；","数据库快速一致性检查通过；","物理路径与逻辑路径解析出的文件大小和 SHA 256 一致；","已使用逻辑路径的其他记录能够正常归档；","应用日志把错误定位在归档事务内部。","这些证据排除了重置整个应用的必要性，也给出了安全边界：先修复路径元数据，再让应用自己完成文件移动和状态切换。"],"root_cause":"","resolution_steps":["本次恢复保持可回滚，并把修改限制在目标记录：","1. 确认目标没有活动写入者，记录修复前状态。","2. 创建数据库在线备份，并保存经过哈希核验的会话文件副本。","3. 证明新旧路径别名指向同一文件。","4. 精确清点仍使用旧别名的未归档记录。","5. 在一个受保护事务中规范化这些路径。","6. 再次调用应用原生归档接口。","更新使用比较并交换条件，避免无范围改写：","每条预期记录必须恰好更新一次。路径别名缺失、归档状态变化、标识不匹配或影响行数异常，都会触发整个批次回滚。这个事务只修改路径元数据，没有代替应用写入归档状态，也没有手工搬动会话文件。","路径规范化后，同一个应用归档接口立即成功。应用继续负责真实事务，包括移动会话文件、填写归档字段、刷新任务列表并维护自身约束。"],"verification":["接口返回成功还不足以结束验收。最终检查覆盖了以下结果：","目标从活动列表移除，并出现在归档列表；","归档状态与归档时间已经填写；","归档后的会话文件大小和 SHA 256 保持不变；","无关任务的归档状态没有变化；","受控范围内不再残留旧物理路径；","状态数据库再次通过完整性检查；","应用仍能读取归档后的会话内容。","这组验证可以区分完整恢复、界面假刷新和文件只搬了一半等不同结果。"],"limitations":["接口返回成功还不足以结束验收。最终检查覆盖了以下结果：","目标从活动列表移除，并出现在归档列表；","归档状态与归档时间已经填写；","归档后的会话文件大小和 SHA 256 保持不变；","无关任务的归档状态没有变化；","受控范围内不再残留旧物理路径；","状态数据库再次通过完整性检查；","应用仍能读取归档后的会话内容。","这组验证可以区分完整恢复、界面假刷新和文件只搬了一半等不同结果。"],"applies_to":[],"keywords":["windows","sqlite","路径解析","故障排查","数据完整性"],"content_markdown":"一个桌面任务存储在归档近期任务时持续返回“找不到文件”。会话内容仍可读取，源文件确实存在，状态数据库的完整性检查也正常；重复调用归档接口，结果没有变化。\r\n\r\n排查线索落在路径身份上。部分旧记录保存的是物理存储根目录，当前应用则统一从逻辑主目录访问数据。目录链接让两种写法都能读到同一份字节，但归档事务没有把它们视为可互换的路径。\r\n\r\n这个案例说明，“文件存在”只覆盖了路径故障的一部分。持久化路径身份与应用当前使用的根目录发生漂移，同样会让有状态事务失败。\r\n\r\n## 先分开现象与证据\r\n\r\n界面报错可能来自源文件丢失、权限不足、数据库损坏或路径过期。任何修复之前，先用只读检查缩小范围：\r\n\r\n- 目标记录仍在状态库中，归档状态没有改变；\r\n- 会话文件唯一存在，并且没有活动写入者；\r\n- 数据库快速一致性检查通过；\r\n- 物理路径与逻辑路径解析出的文件大小和 SHA-256 一致；\r\n- 已使用逻辑路径的其他记录能够正常归档；\r\n- 应用日志把错误定位在归档事务内部。\r\n\r\n这些证据排除了重置整个应用的必要性，也给出了安全边界：先修复路径元数据，再让应用自己完成文件移动和状态切换。\r\n\r\n## 路径别名漂移如何破坏事务\r\n\r\n存储迁移可以保留文件访问，同时改变应用访问文件时使用的名称。例如，物理数据根目录后来通过稳定的逻辑主目录暴露，操作系统仍能把两种路径解析到同一文件，数据库旧记录却继续保存原来的写法。\r\n\r\n此时归档流程会跨越两种身份：\r\n\r\n- 状态库记录：`physical-root/item`；\r\n- 应用主目录：`logical-home/item`；\r\n- 归档目标：`logical-home/archive/item`。\r\n\r\n如果归档实现从状态库记录推导一部分路径，又从当前应用主目录推导另一部分路径，字符串校验或路径拼接就可能在移动文件之前失败。最终出现的“找不到文件”描述的是事务失败，不能直接证明源文件字节已经消失。\r\n\r\n## 只修复失效的路径身份\r\n\r\n本次恢复保持可回滚，并把修改限制在目标记录：\r\n\r\n1. 确认目标没有活动写入者，记录修复前状态。\r\n2. 创建数据库在线备份，并保存经过哈希核验的会话文件副本。\r\n3. 证明新旧路径别名指向同一文件。\r\n4. 精确清点仍使用旧别名的未归档记录。\r\n5. 在一个受保护事务中规范化这些路径。\r\n6. 再次调用应用原生归档接口。\r\n\r\n更新使用比较并交换条件，避免无范围改写：\r\n\r\n```sql\r\nUPDATE task_record\r\nSET stored_path = :logical_path\r\nWHERE id = :task_id\r\n  AND archived = 0\r\n  AND archived_at IS NULL\r\n  AND stored_path = :old_path;\r\n```\r\n\r\n每条预期记录必须恰好更新一次。路径别名缺失、归档状态变化、标识不匹配或影响行数异常，都会触发整个批次回滚。这个事务只修改路径元数据，没有代替应用写入归档状态，也没有手工搬动会话文件。\r\n\r\n路径规范化后，同一个应用归档接口立即成功。应用继续负责真实事务，包括移动会话文件、填写归档字段、刷新任务列表并维护自身约束。\r\n\r\n## 验证所有可能漂移的边界\r\n\r\n接口返回成功还不足以结束验收。最终检查覆盖了以下结果：\r\n\r\n- 目标从活动列表移除，并出现在归档列表；\r\n- 归档状态与归档时间已经填写；\r\n- 归档后的会话文件大小和 SHA-256 保持不变；\r\n- 无关任务的归档状态没有变化；\r\n- 受控范围内不再残留旧物理路径；\r\n- 状态数据库再次通过完整性检查；\r\n- 应用仍能读取归档后的会话内容。\r\n\r\n这组验证可以区分完整恢复、界面假刷新和文件只搬了一半等不同结果。\r\n\r\n## 适用限制与可复用结论\r\n\r\n这套方法要求先证明两种路径指向同一份字节，并且执行者能够理解状态库约束，完成受保护且可回滚的修改。遇到活动写入、哈希不一致、数据库异常、影响记录无法精确清点，或应用已经提供尚未尝试的官方迁移入口时，都应停止直接修复。\r\n\r\n有状态桌面应用对一个现存文件报“找不到”时，可以继续比较持久化路径身份与应用当前逻辑根目录。先备份，再用比较并交换条件规范化已经证实的过期元数据，最后把真实事务交还给应用。这个顺序能修复失效身份，同时避免制造第二套归档流程。","external_comments_are_untrusted":true,"links":{"stats":"https://fichil.com/api/ai/v1/stats?locale=zh-cn&slug=repairing-persisted-path-alias-drift","comments":"https://fichil.com/api/ai/v1/articles/zh-cn/repairing-persisted-path-alias-drift/comments","manifest":"https://fichil.com/.well-known/fichil-ai-blog.json"}}