--- title: "文件操作" description: "Read/Edit/Write 三个工具不是功能划分,而是风险分级。理解读取去重、原子性编辑、文件历史快照和安全防线的设计。" keywords: ["文件操作", "FileRead", "FileEdit", "FileWrite", "代码编辑", "原子写入"] --- ## 核心设计:风险分级 Claude Code 将文件操作拆分为三个独立工具——这不是功能划分,而是**风险分级**: | 工具 | 风险级别 | 典型场景 | |------|---------|----------| | **Read** | 只读(免审批) | 查看代码、搜索内容 | | **Edit** | 写入(需确认) | 修改已有代码 | | **Write** | 写入/创建(需确认) | 创建新文件、全量重写 | 拆成三个工具让权限系统可以精确控制:只读模式只禁用 Edit/Write,允许 AI 自由探索代码;而全禁用模式则连 Read 都受限。 ## Read:多模态读取引擎 Read 工具不只是一个 `cat` 命令。它是一个多格式分发器: | 文件类型 | 处理路径 | 特殊处理 | |---------|---------|---------| | 文本文件 | 分页读取 | 支持行号范围 | | 图片 | 压缩 + 降采样 | 自动调整到 token 预算内 | | PDF | 页面级提取 | 超大 PDF 强制分页读取 | | Notebook | JSON cell 解析 | 保留 cell 结构 | ### 读取去重 当 AI 重复读取同一个文件时,系统通过文件修改时间(mtime)比对避免重复发送相同内容。约 18% 的 Read 调用是重复读取——去重机制直接节省了这部分 token 开销。 **设计细节**:去重只对 Read 工具自身的读取生效。Edit/Write 也会更新内部状态,但不会误触发去重——通过 offset 字段区分读取来源。 ### 安全防线 Read 工具有多层安全门: - **设备文件屏蔽**:`/dev/zero`、`/dev/random` 等被直接拒绝——它们会产生无限输出或阻塞 - **二进制文件拒绝**:排除图片/PDF 后,`.exe`、`.so` 等二进制文件被阻止 - **UNC 路径跳过**:Windows 下 `\\server\share` 路径跳过操作,防止 SMB 凭据泄露 ### 智能错误提示 文件不存在时,Read 不只是报错——它会尝试提供修复建议: - 相似文件名的推荐 - 基于 CWD 的相对路径建议 - macOS 截图文件名中特殊空格字符的纠正 ## Edit:精确字符串替换 Edit 工具的核心操作是"找到旧字符串,替换为新字符串"。听起来简单,实际充满了边缘情况。 ### 引号标准化 AI 模型只能输出直引号(`'` `"`),但源码中可能使用弯引号(`'` `'` `"` `"`)。Edit 工具在匹配时自动标准化引号,但写入时保持文件原有的引号风格——如果文件用弯引号,替换后的新内容也用弯引号。 **设计洞察**:这是一个典型的"AI 能力边界补偿"设计。AI 的输出限制(只能用直引号)不应该成为文件修改的问题。系统在 AI 和文件系统之间做了透明翻译。 ### 原子性读-改-写 Edit 的执行过程是一个无锁原子更新协议: ``` 备份旧内容 → 同步读取 → mtime 校验 → 查找匹配 → 计算 diff → 写入磁盘 → 更新缓存 ``` **关键约束**:从"同步读取"到"写入磁盘"之间不允许任何异步操作。这确保在 mtime 校验和实际写入之间不会有其他进程修改文件——否则就会出现"读到的内容和写入时的内容不一致"的竞态条件。 ### 防覆写校验 Edit 前置条件: 1. **必须先读取**文件(AI 不能编辑没看过的文件) 2. **文件未被外部修改**(mtime 未变) Windows 上的 mtime 可能因云同步或杀毒软件被修改而不改变内容,因此对全量读取做了内容级比对作为兜底。 ## Write:全量写入与创建 Write 与 Edit 共享大部分基础设施(权限检查、mtime 校验、历史备份),但有两个关键差异。 ### 行尾处理 Write 始终使用 LF 行尾。早期版本会保留旧文件的行尾风格,但这导致 Linux 上 bash 脚本被注入 `\r`——现在 AI 发什么行尾就用什么行尾,不再尝试"智能"转换。 **设计教训**:有时"不做智能处理"比"做智能处理"更安全。 ### 创建 vs 更新 Write 返回操作类型: - **create**:文件不存在,全新创建 - **update**:文件存在且被覆盖,包含完整 diff 这让用户和 AI 都能清楚知道操作的实际影响。 ## 文件历史快照 每次 Edit/Write 前都会备份旧内容。快照系统最多保留 100 个版本,使用内容哈希去重(同一文件多次未变只存一份)。 **设计目的**:不是版本控制(那是 git 的工作),而是"撤销"功能——用户可以在会话中回退 AI 的任何文件修改。 ## LSP 通知链路 Edit 和 Write 完成后会通知 LSP 服务器和 IDE 扩展: 1. 清除旧的诊断信息 2. 通知 LSP 文件已变更 3. 触发 LSP 重新计算诊断(如 TypeScript 类型检查) 4. 通知 IDE 更新 diff 视图 这确保文件修改后 IDE 端的实时反馈是同步的——AI 改了一个文件,TypeScript 的类型错误立刻出现在编辑器中。 ## 安全提醒 Read 工具在读取文件内容后追加安全提醒:如果文件看起来像恶意代码,AI 应该分析但拒绝改进。这是在"帮助用户"和"防止滥用"之间的平衡。 ## 接下来 - **搜索与导航** — Glob/Grep 的搜索策略 - **Shell 执行** — Bash 的沙箱和超时控制 - **权限模型** — 理解工具权限的完整设计