# 离线 Binlog 文件遍历

`BinlogFileReader` 顺序遍历一份已经读入内存的、未加密的 MySQL 8.0.x Binlog 文件字节。输入为从文件标识开始的 `BytesView`，本层不打开文件、不追加输入，也不自动解码表映射、行变化或事务。

## 创建与读取

`BinlogFileReader::new(data, max_event_size?)` 校验四字节文件标识与事件大小配置，初始游标为 4。事件按需在 `next()` 时校验，因此创建成功不代表整份文件有效。

- `next()` 返回 `Some(BinlogFileEvent)`，每次只消费一个完整且通过格式/校验检查的事件。
- 首个事件必须为 FORMAT_DESCRIPTION_EVENT；只有 magic 的输入也会返回 `MissingFormatDescription`，不视为完整空文件。
- 已经读取 FDE 且游标恰好位于输入结尾时，返回 `None`；重复读取仍为 `None`，位置与格式保持不变。
- `position()` 返回下一个事件的真实物理起点；发生错误后保持为失败事件的起点。
- `format()` 在读取首个 FDE 前为 `None`，之后返回当前有效上下文。

读取必须持续到 `None`，才能确认全部输入通过本层检查。若提前停止，尚未读取的尾部不受保证。

## 返回值和格式生命周期

每个 `BinlogFileEvent` 包含：

| 字段 | 含义 |
| --- | --- |
| `header` | 公共事件头，含类型、长度、标志及真实物理位置 |
| `raw` | 当前事件的完整原始视图，包括公共头和可能的 CRC 尾部 |
| `body` | 去除公共头和 CRC 后的内容；OFF 模式保留头后的全部内容 |
| `format` | 此事件使用的、已经验证的格式上下文 |

FDE 自身始终验证 CRC，它的 `body` 仍包含末尾的 checksum-algorithm 描述字节。FDE 返回的 `format` 是它刚刚建立的新上下文。后续每个 FDE 都独立解析并替换上下文，允许 CRC32 与 OFF 策略切换；不会用旧 OFF 策略绕过新 FDE 的 CRC。

返回视图不会复制完整事件，但会保留底层输入字节的引用。旧事件与其格式快照不受后续读取或失败影响。读者需要控制持有时间，避免为保存少量事件而长期保留整份文件。

## 偏移、长度和未知事件

游标只按成功解析的 `event_size` 增加，不使用头中的 `next_position` 跳转。文件中的 `next_position` 保留原值，不在本层检查它与真实位置的一致性。输入为更大字节序列的切片时，物理偏移相对于传入视图的起点计算。

本层复用既有事件头、完整事件和校验接口：先限制 UInt32 事件长度，再验证剩余数据是否足够，最后转为索引。默认单事件上限为 16 MiB，配置必须至少为 19。FDE 和每个后续事件都受此限制。

未知类型也返回原始事件，包括超出 FDE 长度表范围的类型码；它们仍必须通过长度和当前 CRC 策略检查。TABLE_MAP、ROWS、QUERY 等已知类型在本层同样不检查 body 业务语义。完整性校验成功不意味着这些内容可以被对应的业务解码器接受。

## 错误与恢复

残缺公共头返回 `TruncatedInput`，完整头后缺少事件内容返回 `TruncatedEvent`。错误文件标识、非法大小、CRC 错误和不支持的格式继续使用现有 `DecodeError`。

`next()` 中任意错误都会清除格式上下文并永久停止当前读者。再次调用返回 `FileReaderFailed`，不能跳过错误继续解析。修复输入后应创建新的读者；本层不搜索 magic、猜测事件边界或支持中间偏移恢复。

## 与行事件、事务解码器组合

遍历器返回 `raw` 和 `header.file_offset`，调用者可将它们交给 `TableMapContext` 或 `TransactionDecoder`。遇到新 FDE 时，调用者必须重建或重置依赖旧格式的上层上下文。

事务解码器只接受明确的连续 BEGIN 到提交/回滚区间。文件级 GTID、ROTATE 等事件虽然可以被遍历，本层不会将它们转换为事务解码器支持的事件。不能在事务内部随意过滤未知事件；此类事件仍应令上层事务失败。

文件在完整事件边界结束只说明没有残缺事件，不说明事务已经提交。调用者仍须在事务输入结束时调用 `TransactionDecoder::finish()`。如果文件遍历本身失败，也应丢弃活动的上层状态，不能拿新读者的数据继续拼接旧事务。

## 验证与限制

本批测试复用此前由 Python struct/zlib 独立生成的 FDE、CRC/OFF、事务及错误事件样本，组合为包含文件 magic 的输入，并覆盖每个 FDE/末尾事件的截断点、未知类型、错误重试、大小上限、格式切换、切片偏移及事务集成。没有新增协议样本生成器。

这是对完整内存视图的惰性遍历，并非分块流式 I/O；总文件大小受 BytesView 和可用内存限制。库本层没有文件系统 API、目录轮转、远程订阅或自动语义分发；另有[离线 CLI](cli.md) 封装本地文件读取与统计。后续已补充[三组真实 MySQL 8.0.43 文件验证](mysql-integration.md)。底层支持版本及协议依据沿用[格式与校验说明](format-checksum.md)，本层未扩大协议兼容范围。

收到类型 4 的完整文件事件后，可将 event.format、event.raw 与 event.header.file_offset 交给 RotateEvent::parse，提取目标日志标识及 UInt64 位置，见 [轮转解析](rotate-events.md)。遍历器自身仍只处理当前输入，不自动读取目标文件，也不把轮转视为事务提交。

CLI 另提供 --chain，显式按顺序读取多份文件并核对末尾轮转连接，见 [多文件事件浏览](cli-chain.md)。这不改变单文件遍历器/轮转解析器本身，也没有增加跨文件行或事务续接。

另有 [BinlogEventStream 和 CLI --stream](cli-stream.md)：调用者逐个提供完整事件，CLI 可逐事件读取单文件。此接口不改变上面 BinlogFileReader 的完整内存视图语义。
