GeWuYou a79f02c987 docs(api): 添加 Core API 参考文档与事件系统接口文档
- 新增 Core API 参考文档,涵盖架构与模块、数据模型与系统、命令与查询等核心组件
- 添加事件系统接口详细文档,包括 IEvent、IEventBus、IUnRegister 等接口说明
- 提供完整的 API 使用示例路径、最佳实践与性能建议
- 包含架构图、依赖关系图与故障排查指南
- 添加测试用例参考与扩展方法说明
- [skip ci]
2026-01-21 23:45:10 +08:00

380 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 存储系统
<cite>
**本文引用的文件列表**
- [IStorage.cs](file://GFramework.Core.Abstractions/storage/IStorage.cs)
- [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs)
- [IScopedStorage.cs](file://GFramework.Game.Abstractions/storage/IScopedStorage.cs)
- [ISerializer.cs](file://GFramework.Game.Abstractions/serializer/ISerializer.cs)
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs)
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs)
- [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs)
- [ReadMe.md](file://GFramework.Game/storage/ReadMe.md)
- [GodotFileStorage.cs](file://GFramework.Godot/storage/GodotFileStorage.cs)
- [CachedStorage.cs](file://GFramework.Game/README.md)
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs)
- [ISettingsPersistence.cs](file://GFramework.Game.Abstractions/setting/ISettingsPersistence.cs)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [组件详解](#组件详解)
6. [依赖关系分析](#依赖关系分析)
7. [性能与优化](#性能与优化)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向GFramework存储系统聚焦于FileStorage文件存储实现、ScopedStorage作用域存储策略、以及IStorage/IFileStorage/IScopedStorage接口的设计理念。文档涵盖文件读写流程、路径管理与安全校验、错误处理机制、作用域隔离与命名空间控制、以及在游戏开发中的典型应用场景配置、存档、临时缓存。同时提供配置选项、API参考与实践示例并总结数据持久化的最佳实践、安全性与性能优化建议。
## 项目结构
存储系统由“抽象接口层”“具体实现层”“序列化器层”“应用集成层”组成:
- 抽象接口层定义统一的存储契约IStorage、IFileStorage、IScopedStorage
- 具体实现层FileStorage通用文件系统、ScopedStorage作用域包装器、GodotFileStorageGodot引擎专用
- 序列化器层ISerializer及JsonSerializer负责对象与文本的双向转换。
- 应用集成层SettingsPersistence等业务组件通过IStorage进行设置的加载/保存/删除。
```mermaid
graph TB
subgraph "抽象接口层"
IStorage["IStorage 接口"]
IFileStorage["IFileStorage 接口"]
IScopedStorage["IScopedStorage 接口"]
ISerializer["ISerializer 接口"]
end
subgraph "实现层"
FileStorage["FileStorage 实现"]
ScopedStorage["ScopedStorage 实现"]
GodotFileStorage["GodotFileStorage 实现"]
end
subgraph "序列化器层"
JsonSerializer["JsonSerializer 实现"]
end
subgraph "应用集成层"
SettingsPersistence["SettingsPersistence 业务组件"]
end
IFileStorage --> IStorage
IScopedStorage --> IStorage
FileStorage --> IFileStorage
ScopedStorage --> IScopedStorage
GodotFileStorage --> IStorage
FileStorage --> ISerializer
GodotFileStorage --> ISerializer
JsonSerializer --> ISerializer
SettingsPersistence --> IStorage
```
图表来源
- [IStorage.cs](file://GFramework.Core.Abstractions/storage/IStorage.cs#L1-L72)
- [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs#L1-L9)
- [IScopedStorage.cs](file://GFramework.Game.Abstractions/storage/IScopedStorage.cs#L1-L8)
- [ISerializer.cs](file://GFramework.Game.Abstractions/serializer/ISerializer.cs#L1-L25)
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L1-L258)
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs#L1-L99)
- [GodotFileStorage.cs](file://GFramework.Godot/storage/GodotFileStorage.cs#L1-L291)
- [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs#L1-L29)
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs#L1-L39)
章节来源
- [IStorage.cs](file://GFramework.Core.Abstractions/storage/IStorage.cs#L1-L72)
- [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs#L1-L9)
- [IScopedStorage.cs](file://GFramework.Game.Abstractions/storage/IScopedStorage.cs#L1-L8)
- [ISerializer.cs](file://GFramework.Game.Abstractions/serializer/ISerializer.cs#L1-L25)
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L1-L258)
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs#L1-L99)
- [GodotFileStorage.cs](file://GFramework.Godot/storage/GodotFileStorage.cs#L1-L291)
- [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs#L1-L29)
- [ReadMe.md](file://GFramework.Game/storage/ReadMe.md#L1-L135)
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs#L1-L39)
## 核心组件
- IStorage统一的存储接口定义读写、存在检查、异步操作与删除等能力。
- IFileStorage面向文件系统的存储接口继承自IStorage。
- IScopedStorage作用域存储接口继承自IStorage提供命名空间隔离。
- FileStorage基于文件系统的通用实现支持同步/异步读写、路径安全校验、细粒度锁。
- ScopedStorage作用域包装器为所有键添加前缀支持嵌套作用域。
- ISerializer/JsonSerializer序列化器接口与JSON实现负责对象与字符串的互转。
- SettingsPersistence设置持久化业务组件基于IStorage实现设置的加载/保存/删除。
章节来源
- [IStorage.cs](file://GFramework.Core.Abstractions/storage/IStorage.cs#L1-L72)
- [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs#L1-L9)
- [IScopedStorage.cs](file://GFramework.Game.Abstractions/storage/IScopedStorage.cs#L1-L8)
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L1-L258)
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs#L1-L99)
- [ISerializer.cs](file://GFramework.Game.Abstractions/serializer/ISerializer.cs#L1-L25)
- [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs#L1-L29)
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs#L1-L39)
## 架构总览
存储系统采用“接口抽象 + 多实现 + 装饰器包装”的架构:
- 接口层提供统一契约,屏蔽具体实现差异。
- FileStorage/GodotFileStorage分别适配通用文件系统与Godot虚拟路径。
- ScopedStorage通过装饰器模式为任意IStorage增加命名空间隔离。
- SettingsPersistence等业务组件仅依赖IStorage便于替换与扩展。
```mermaid
classDiagram
class IStorage {
+Exists(key) bool
+ExistsAsync(key) Task~bool~
+Read~T~(key) T
+Read~T~(key, defaultValue) T
+ReadAsync~T~(key) Task~T~
+Write~T~(key, value) void
+WriteAsync~T~(key, value) Task
+Delete(key) void
}
class IFileStorage
class IScopedStorage
class FileStorage
class ScopedStorage
class GodotFileStorage
class ISerializer
class JsonSerializer
class SettingsPersistence
IFileStorage --|> IStorage
IScopedStorage --|> IStorage
FileStorage ..|> IFileStorage
ScopedStorage ..|> IScopedStorage
GodotFileStorage ..|> IStorage
FileStorage --> ISerializer
GodotFileStorage --> ISerializer
JsonSerializer ..|> ISerializer
SettingsPersistence --> IStorage
```
图表来源
- [IStorage.cs](file://GFramework.Core.Abstractions/storage/IStorage.cs#L1-L72)
- [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs#L1-L9)
- [IScopedStorage.cs](file://GFramework.Game.Abstractions/storage/IScopedStorage.cs#L1-L8)
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L1-L258)
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs#L1-L99)
- [GodotFileStorage.cs](file://GFramework.Godot/storage/GodotFileStorage.cs#L1-L291)
- [ISerializer.cs](file://GFramework.Game.Abstractions/serializer/ISerializer.cs#L1-L25)
- [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs#L1-L29)
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs#L1-L39)
## 组件详解
### FileStorage 文件存储实现
- 设计目标:提供基于文件系统的可靠持久化能力,支持同步/异步读写、路径安全校验、细粒度锁保证线程安全。
- 关键特性:
- 路径安全:禁止“..”路径逃逸;清理非法文件名字符;自动创建目录。
- 锁机制:按路径生成独立锁对象,避免跨键竞争,提升并发性能。
- 序列化通过ISerializer完成对象与字符串的转换。
- 扩展名:默认“.dat”可通过构造参数定制。
- 主要方法与流程:
- 路径转换ToPath规范化分隔符、清理段名、拼接根路径与扩展名。
- 读取Read/ReadAsync先加锁再读取文件内容最后反序列化。
- 写入Write/WriteAsync先序列化再加锁写入文件。
- 存在检查Exists/ExistsAsync加锁判断文件是否存在。
- 删除Delete加锁删除文件。
- 错误处理:
- 读取不存在键时抛出FileNotFoundException。
- 读取重载Read<T>(key, defaultValue)提供默认值避免异常。
- 路径校验失败抛出ArgumentException。
- 性能要点:
- 异步读写仍需加锁但IO可异步进行减少阻塞。
- 并发访问不同键可并行,同一键串行执行。
```mermaid
flowchart TD
Start(["调用 Read<T>(key)"]) --> ToPath["ToPath(key)<br/>规范化/清理/拼接路径"]
ToPath --> Lock["获取/创建键级锁"]
Lock --> CheckExist{"文件存在?"}
CheckExist --> |否| ThrowErr["抛出 FileNotFoundException"]
CheckExist --> |是| ReadFile["读取文件内容"]
ReadFile --> Deserialize["反序列化为 T"]
Deserialize --> Return["返回结果"]
ThrowErr --> End(["结束"])
Return --> End
```
图表来源
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L144-L157)
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L200-L209)
章节来源
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L1-L258)
- [ReadMe.md](file://GFramework.Game/storage/ReadMe.md#L1-L135)
### ScopedStorage 作用域存储策略
- 设计目标:通过前缀为所有键添加命名空间隔离,实现逻辑分组与数据范围控制,支持嵌套作用域。
- 关键特性:
- 前缀拼接Key(key)将prefix与key组合为“prefix/key”。
- 嵌套作用域Scope(scope)返回新的ScopedStorage前缀叠加。
- 透明包装所有IStorage操作均转发到底层inner存储。
- 同步/异步:与底层存储保持一致的异步能力。
- 使用场景:
- 将玩家数据、游戏存档、全局设置分组到不同作用域,避免键冲突。
- 嵌套作用域用于更细粒度的组织如settings/audio/master_volume
- 注意事项:
- 前缀为空时直接使用原键。
- 与底层存储共享物理存储,注意键冲突与命名规范。
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Scoped as "ScopedStorage"
participant Inner as "内部存储(IStorage)"
Client->>Scoped : Write(key, value)
Scoped->>Scoped : Key(key) -> "prefix/key"
Scoped->>Inner : Write("prefix/key", value)
Inner-->>Scoped : 完成
Scoped-->>Client : 返回
```
图表来源
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs#L63-L73)
章节来源
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs#L1-L99)
- [ReadMe.md](file://GFramework.Game/storage/ReadMe.md#L60-L121)
### 接口设计IStorage/IFileStorage/IScopedStorage
- IStorage定义统一的读写、存在检查、异步与删除能力是所有存储实现的基础契约。
- IFileStorage面向文件系统的扩展接口强调文件语义扩展名、路径等
- IScopedStorage强调命名空间隔离与作用域管理便于多模块/多功能的数据分区。
- 设计理念:
- 抽象先行:通过接口屏蔽实现细节,便于替换与扩展。
- 统一契约所有实现遵循相同的API降低学习成本与迁移成本。
- 可组合通过装饰器如ScopedStorage增强功能不侵入核心实现。
章节来源
- [IStorage.cs](file://GFramework.Core.Abstractions/storage/IStorage.cs#L1-L72)
- [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs#L1-L9)
- [IScopedStorage.cs](file://GFramework.Game.Abstractions/storage/IScopedStorage.cs#L1-L8)
### 序列化器ISerializer/JsonSerializer
- ISerializer定义Serialize/Deserialize通用方法解耦存储与序列化技术。
- JsonSerializer基于Newtonsoft.Json实现提供对象与JSON字符串的互转。
- 使用建议:
- 选择与数据结构匹配的序列化器JSON适合结构化数据二进制/自定义格式适合性能敏感场景)。
- 注意反序列化失败时的异常处理与默认值策略。
章节来源
- [ISerializer.cs](file://GFramework.Game.Abstractions/serializer/ISerializer.cs#L1-L25)
- [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs#L1-L29)
### 应用集成SettingsPersistence
- 通过IStorage实现设置的异步加载、保存、存在检查与删除。
- 与事件系统配合,发出加载/应用/保存等事件,便于观察状态变化。
- 适用于游戏配置、音量、难度等设置的持久化管理。
章节来源
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs#L1-L39)
- [ISettingsPersistence.cs](file://GFramework.Game.Abstractions/setting/ISettingsPersistence.cs#L1-L43)
## 依赖关系分析
- FileStorage依赖ISerializer进行序列化依赖路径工具与文件系统API使用ConcurrentDictionary维护键级锁。
- ScopedStorage依赖IStorage通过装饰器模式透明包装任何存储实现。
- SettingsPersistence依赖IStorage与事件系统实现设置的生命周期管理。
- GodotFileStorage为Godot引擎特化实现兼容res://与user://虚拟路径提供Godot FileAccess支持。
```mermaid
graph LR
FileStorage --> ISerializer
ScopedStorage --> IStorage
GodotFileStorage --> ISerializer
SettingsPersistence --> IStorage
```
图表来源
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L1-L258)
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs#L1-L99)
- [GodotFileStorage.cs](file://GFramework.Godot/storage/GodotFileStorage.cs#L1-L291)
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs#L1-L39)
章节来源
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L1-L258)
- [ScopedStorage.cs](file://GFramework.Game/storage/ScopedStorage.cs#L1-L99)
- [GodotFileStorage.cs](file://GFramework.Godot/storage/GodotFileStorage.cs#L1-L291)
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs#L1-L39)
## 性能与优化
- 并发与锁:
- FileStorage按键级锁不同键可并行同一键串行避免竞态。
- GodotFileStorage同理按键级锁保障线程安全。
- 异步IO
- FileStorage/ScopedStorage在读取时可使用异步IO注意锁范围
- GodotFileStorage ReadAsync通过Task.Run包装同步读取简化调用。
- 缓存策略:
- 可使用CachedStorage对热点数据进行内存缓存减少重复IO。
- 缓存过期时间可配置默认5分钟支持清空缓存与清空存储。
- 写入优化:
- 批量写入优于频繁小写入;可缓冲后再一次性写入。
- 合理拆分键层级,避免单文件过大导致读写压力集中。
- 路径与序列化:
- 使用合理扩展名与目录结构,便于备份与迁移。
- 选择合适的序列化器,平衡可读性、体积与性能。
章节来源
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L1-L258)
- [GodotFileStorage.cs](file://GFramework.Godot/storage/GodotFileStorage.cs#L1-L291)
- [CachedStorage.cs](file://GFramework.Game/README.md#L550-L647)
## 故障排查指南
- 常见问题与定位:
- “存储键不存在”FileStorage读取会抛出FileNotFoundException建议使用Read<T>(key, defaultValue)提供默认值。
- “路径包含‘..ToPath会拒绝包含“..”的键抛出ArgumentException请使用合法路径。
- “文件名包含非法字符”SanitizeSegment会替换非法字符为下划线请避免使用不可用字符。
- “权限不足”:确保程序对存储目录具有读写权限。
- “序列化失败”JsonSerializer反序列化失败会抛出ArgumentException检查数据格式与字段映射。
- 调试建议:
- 在关键节点记录日志(键、路径、序列化前后大小)。
- 使用ScopedStorage隔离不同模块缩小问题范围。
- 对高频读写键进行缓存减少IO波动。
章节来源
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L55-L103)
- [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs#L144-L157)
- [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs#L20-L29)
## 结论
GFramework存储系统通过清晰的接口抽象与多种实现为游戏开发提供了灵活、安全且高性能的数据持久化方案。FileStorage提供通用文件存储能力ScopedStorage实现命名空间隔离与作用域管理ISerializer解耦序列化技术SettingsPersistence将存储与业务流程结合。配合缓存与异步IO策略可在保证一致性的同时提升性能与可维护性。
## 附录
### API参考IStorage/IFileStorage/IScopedStorage
- IStorage
- Exists(key): 检查键是否存在
- ExistsAsync(key): 异步检查
- Read<T>(key): 读取键值
- Read<T>(key, defaultValue): 读取键值或默认值
- ReadAsync<T>(key): 异步读取
- Write<T>(key, value): 写入键值
- WriteAsync<T>(key, value): 异步写入
- Delete(key): 删除键
- IFileStorage继承IStorage面向文件系统
- IScopedStorage继承IStorage提供作用域包装
章节来源
- [IStorage.cs](file://GFramework.Core.Abstractions/storage/IStorage.cs#L1-L72)
- [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs#L1-L9)
- [IScopedStorage.cs](file://GFramework.Game.Abstractions/storage/IScopedStorage.cs#L1-L8)
### 配置与使用示例
- FileStorage
- 构造FileStorage(rootPath, serializer, extension=".dat")
- 示例:写入/读取/异步读取/存在检查/删除
- ScopedStorage
- 构造ScopedStorage(inner, prefix)
- 示例:作用域前缀、嵌套作用域、异步操作
- SettingsPersistence
- 异步加载/保存/存在检查/删除;发送事件通知
章节来源
- [ReadMe.md](file://GFramework.Game/storage/ReadMe.md#L1-L135)
- [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs#L1-L39)
### 最佳实践
- 命名与分层:使用有意义的键层级与作用域,避免键冲突。
- 默认值策略:读取时提供默认值,避免异常传播。
- 缓存与批处理:对热点数据启用缓存;合并多次写入为批量写入。
- 安全与合规:严格校验键与路径,避免路径逃逸;定期备份重要数据。
- 性能监控关注IO延迟与锁等待必要时引入异步与缓存。