# patch_file 使用指南 > 创建: 2026-06-15 > 关联设计: docs/02-架构设计/专项设计/patch_file工具设计-2026-06-15.md ## 使用场景 局部更新文件(替代 read-merge-write 多步流程),精确定位 `old_text` 并替换为 `new_text`。 适用于只改文件中某几行的场景:大文件改 3 行无需重发全部内容,避免 `write_file` 全量覆盖的事故风险(参见 FR-S7 记录:762 行文件被覆盖为 248 字节)。 ## API 参数 | 参数 | 必填 | 说明 | |------|------|------| | `path` | 是 | 目标文件路径(workspace 内,走 `validate_path` 校验 + 黑名单) | | `old_text` | 是 | 要替换的精确文本(必须与文件内容完全匹配,含空格/缩进;充当乐观锁) | | `new_text` | 是 | 替换后的新文本 | | `line` | 否 | 行号辅助定位(快速跳转 + 去歧增强;有值时优先跳到该行检查 `old_text`,不匹配则降级全文扫描) | | `expected_hash` | 否 | 文件指纹防脏写,格式 `"{unix_timestamp}_{size}"`(如 `"1718400000_12345"`),由 `read_file` 返回的 `file_hash` 字段携带 | 补充去歧参数(可选):`before_text` / `after_text` —— 当 `old_text` 多处匹配时,作为上下文锚精确锁定目标位置。 ## 返回值 ```json { "success": true, "patches_applied": 1, "total_matches": 1, "lines_changed": 2, "warnings": [], "file_hash": "1718400000_12400" } ``` | 字段 | 含义 | |------|------| | `success` | 是否成功 | | `patches_applied` | 成功替换的 patch 数 | | `total_matches` | 每个 patch 的总命中数(含未替换的) | | `lines_changed` | 总行数变化(正=增加,负=减少) | | `warnings` | 警告信息,如 `["匹配到 3 处,仅替换第 1 处"]` | | `file_hash` | 操作后的新指纹(下次操作传入 `expected_hash` 用) | ## 安全边界 - **RiskLevel Medium**:修改已有文件,需人工审批 - **自动 `.bak` 备份**:复用 FR-S7 已有逻辑,误操作可恢复 - **old_text 不匹配 → 报错**(不修改文件,避免盲替换) - **expected_hash 不匹配 → 报错**(防并发脏写,提示「文件已被外部修改,请重新读取」) - **三层防御**:L1 文件级 Mutex(防时机冲突)+ L2 old_text 精确匹配(防内容错配)+ L3 expected_hash 指纹校验(防版本漂移),底层兜底 `.bak` 备份 ## 最佳实践 - **old_text 取足够上下文确保唯一**:避免短串多处匹配,收到「匹配到 N 处」warning 时用 `before_text`/`after_text` 锚定或加长 `old_text` 重试 - **大段修改用多个小 patch 而非一个巨大 patch**:每个 patch 独立校验,失败可定位 - **危险操作前先 `file_info` 确认**:核对路径、大小、是否二进制(含 `\0` 的文件会被拒绝) - **read → patch 链路带上 hash**:`read_file` 返回 `file_hash`,传入 `patch_file` 的 `expected_hash` 形成乐观锁闭环 - **多 patch 从文件末尾往前排**:避免行号偏移(工具内部已按此执行) - **old_text 必须完全匹配**:含空格、缩进、换行,复制粘贴原文最稳妥 ## 示例 ### 基础替换 ```json { "path": "src/main.rs", "old_text": "fn old()", "new_text": "fn new()" } ``` ### 带 hash 乐观锁 ```json { "path": "src/main.rs", "expected_hash": "1718400000_12345", "patches": [ { "old_text": "fn old()", "new_text": "fn new()" } ] } ``` ### 多处匹配用 line 锚定 ```json { "path": "src/main.rs", "old_text": "return Ok(())", "new_text": "return Ok(value)", "line": 42 } ``` ## 边界情况 | 情况 | 行为 | |------|------| | 文件不存在 | 报错「文件不存在」 | | 二进制文件(含 `\0`) | 报错「不支持二进制文件」 | | `old_text` 为空串 | 报错「old_text 不能为空」 | | `new_text` == `old_text` | 成功 + warning「无实际更改」 | | 路径含 `..` | `validate_path` 黑名单拦截 | | 目标是 `.bak`/`.tmp` | 拒绝(CR-03 噪声文件过滤) |