---
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 的沙箱和超时控制
- **权限模型** — 理解工具权限的完整设计
