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

18 KiB
Raw Blame History

Godot文件存储

**本文引用的文件** - [GodotFileStorage.cs](file://GFramework.Godot/storage/GodotFileStorage.cs) - [GodotPathExtensions.cs](file://GFramework.Godot/extensions/GodotPathExtensions.cs) - [IStorage.cs](file://GFramework.Core.Abstractions/storage/IStorage.cs) - [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs) - [ISerializer.cs](file://GFramework.Game.Abstractions/serializer/ISerializer.cs) - [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs) - [README.mdGodot存储模块](file://GFramework.Godot/storage/README.md)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本指南围绕Godot引擎的文件存储系统聚焦GodotFileStorage类的设计与实现系统阐述其对res://、user://虚拟路径与普通文件系统路径的支持机制详解基于key的细粒度锁与ConcurrentDictionary的线程安全策略深入解析Delete、Exists、Read、Write等核心方法的实现逻辑及异步版本的适用场景说明路径处理的安全机制路径验证、非法字符清理、相对路径限制并提供完整的API使用示例、错误处理、性能优化建议与最佳实践以及与ISerializer接口的集成方式与序列化策略。

项目结构

Godot文件存储位于GFramework.Godot模块中核心实现为GodotFileStorage配合路径扩展工具与序列化器接口完成跨平台与Godot生态的适配。

graph TB
subgraph "Godot模块"
GFS["GodotFileStorage.cs"]
GPE["GodotPathExtensions.cs"]
end
subgraph "抽象层"
IS["IStorage.cs"]
IF["IFileStorage.cs"]
SER["ISerializer.cs"]
end
subgraph "具体实现"
JS["JsonSerializer.cs"]
end
subgraph "文档"
DOC["README.mdGodot存储模块"]
end
GFS --> IS
GFS --> SER
GFS --> GPE
JS --> SER
DOC --> GFS
DOC --> GPE

图表来源

章节来源

核心组件

  • GodotFileStorage实现IStorage接口提供线程安全的文件读写、存在性检查与删除能力支持res://、user://与普通文件系统路径。
  • GodotPathExtensions提供IsGodotPath、IsUserPath、IsResPath等扩展方法用于识别Godot虚拟路径。
  • IStorage/ISerializer定义统一的存储接口与序列化契约便于替换不同序列化器如JSON
  • JsonSerializer具体序列化实现负责对象与字符串之间的双向转换。

章节来源

架构总览

GodotFileStorage通过以下层次协作

  • 接口层IStorage定义统一APIIFileStorage继承IStorage形成Godot专用的文件存储接口。
  • 实现层GodotFileStorage实现IStorage内部组合ISerializer进行序列化使用GodotPathExtensions判断路径类型。
  • 平台适配Godot虚拟路径使用FileAccess/DirAccess普通路径使用标准.NET文件API。
  • 线程安全以路径为key的细粒度锁结合ConcurrentDictionary管理锁对象避免全局锁竞争。
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 GodotFileStorage {
-_keyLocks : ConcurrentDictionary~string, object~
-_serializer : ISerializer
+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
-ToAbsolutePath(key) string
-GetLock(path) object
}
class GodotPathExtensions {
+IsUserPath(path) bool
+IsResPath(path) bool
+IsGodotPath(path) bool
}
class ISerializer {
+Serialize~T~(value) string
+Deserialize~T~(data) T
}
class JsonSerializer {
+Serialize~T~(value) string
+Deserialize~T~(data) T
}
IFileStorage --|> IStorage
GodotFileStorage ..|> IStorage
GodotFileStorage --> ISerializer
GodotFileStorage --> GodotPathExtensions
JsonSerializer ..|> ISerializer

图表来源

详细组件分析

GodotFileStorage类设计与实现

  • 设计理念
    • 针对Godot生态定制原生支持res://只读资源、user://(可读写用户数据)与普通文件系统路径。
    • 线程安全以“路径”为key的细粒度锁避免全局锁竞争提升并发吞吐。
    • 序列化解耦通过ISerializer抽象允许切换JSON、二进制等序列化策略。
  • 关键字段与构造
    • _keyLocksConcurrentDictionary<string, object>,按路径维护独立锁对象。
    • _serializerISerializer实例负责对象与字符串的序列化/反序列化。
    • 构造函数注入ISerializer若为空则抛出异常。
  • 路径处理与安全
    • ToAbsolutePath规范化斜杠、禁止“..”、区分Godot路径与普通路径对普通路径进行段级非法字符清理与目录自动创建。
    • SanitizeSegment将无效文件名字符替换为下划线降低跨平台兼容性问题。
    • GetLock按路径获取或新增锁对象避免锁字典无限增长后及时清理。
  • 核心方法实现
    • Exists/ExistsAsync根据路径类型选择FileAccess.FileExists或File.Exists异步版本采用Task.FromResult包装。
    • Read/Read/ReadAsync先打开文件再调用_serializer.Deserialize普通路径使用UTF-8编码读取文本。
    • Write/WriteAsync先序列化再写入Godot路径使用FileAccess普通路径使用File.WriteAllText。
    • Delete支持Godot路径DirAccess.RemoveAbsolute与普通路径File.Delete完成后尝试移除锁。
  • 异步版本使用场景
    • ReadAsync适合长时间IO或需要避免阻塞UI线程的场景内部仍使用lock保护避免竞态。
    • WriteAsync适合批量写入或后台持久化内部仍使用lock保证原子性。
  • 错误处理
    • ArgumentException空路径、包含“..”、无效键。
    • FileNotFoundException读取不存在文件时抛出。
    • IOExceptionGodot路径删除失败时抛出。

章节来源

路径处理与安全机制

  • 路径类型
    • res://只读资源路径随游戏打包使用FileAccess.Open/Exists。
    • user://可读写用户数据路径Godot用户目录使用FileAccess.Open/Exists/RemoveAbsolute。
    • 普通路径完整文件系统访问使用File.Exists/ReadAllText/WriteAllText/Delete。
  • 安全控制
    • 非法字符清理SanitizeSegment将无效文件名字符替换为下划线。
    • 相对路径限制:禁止“..”,防止路径逃逸。
    • 目录自动创建:普通路径写入前确保父目录存在。
  • 路径验证流程图
flowchart TD
Start(["输入存储键"]) --> Normalize["规范化斜杠 '/'"]
Normalize --> CheckDotDot{"包含 '..' ?"}
CheckDotDot --> |是| ThrowArg["抛出ArgumentException"]
CheckDotDot --> |否| IsGodot{"是否Godot路径(res:// 或 user://)?"}
IsGodot --> |是| ReturnGodot["直接返回Godot路径"]
IsGodot --> |否| Split["按'/'分割并去空"]
Split --> ValidateSegs{"段数 > 0 ?"}
ValidateSegs --> |否| ThrowArg2["抛出ArgumentException"]
ValidateSegs --> |是| BuildDir["组合目录段"]
BuildDir --> CreateDir["确保目录存在"]
CreateDir --> Combine["拼接文件名"]
Combine --> ReturnAbs["返回绝对路径"]
ThrowArg --> End(["结束"])
ThrowArg2 --> End
ReturnGodot --> End
ReturnAbs --> End

图表来源

章节来源

线程安全与并发模型

  • 细粒度锁
    • _keyLocks以“绝对路径”为key的锁字典每个文件路径拥有独立锁对象。
    • GetLock按路径获取或新增锁对象Delete完成后TryRemove移除无用锁避免内存膨胀。
  • 并发策略
    • 读写操作均在对应路径锁内执行,避免同一文件的并发冲突。
    • 不同文件路径可并发访问,显著降低锁竞争。
  • 锁生命周期
    • 仅在必要时持有锁,尽量缩短临界区;读取阶段可共享读取,写入阶段独占。

章节来源

与ISerializer接口的集成

  • ISerializer契约
    • Serialize将对象序列化为字符串。
    • Deserialize将字符串反序列化为对象。
  • JsonSerializer实现
    • 使用Newtonsoft.Json进行序列化/反序列化默认UTF-8编码。
    • 反序列化失败时抛出ArgumentException。
  • 集成方式
    • GodotFileStorage在Read/Write中调用ISerializer实现与具体序列化策略解耦。
    • 可替换为二进制序列化器以获得更高性能与更小体积。

章节来源

API使用示例与最佳实践

  • 基本使用
    • 写入用户数据Write("user://player.dat", userData)
    • 读取用户数据Read("user://player.dat")
  • 异步操作
    • 异步写入配置WriteAsync("user://config.json", config)
    • 异步读取配置ReadAsync("user://config.json")
  • 不同路径类型
    • 读取资源Read("res://levels/level_001.json")
    • 存储用户存档Write("user://saves/slot_001.dat", saveData)
    • 存储调试信息Write("logs/debug_...json", debugLog)
  • 存在性检查与默认值
    • Exists("user://settings.json") + Read(key, default)
  • 错误处理
    • 捕获FileNotFoundException文件不存在时回退默认值或初始化新数据。
    • 捕获ArgumentException路径不合法空、包含“..”、无效键)。
    • 捕获IOExceptionGodot路径删除失败或写入权限不足。
  • 性能优化建议
    • 批量读写时优先使用异步方法,避免阻塞主线程。
    • 避免频繁的小文件操作,合并写入或使用缓存。
    • 选择合适的序列化器JSON便于调试二进制更高效。
  • 最佳实践
    • 资源文件使用res://用户数据使用user://,临时调试使用普通路径。
    • 总是处理FileNotFoundException使用带默认值的Read重载。
    • 在高并发场景下,尽量减少锁持有时间,避免长耗时操作在锁内执行。

章节来源

依赖关系分析

  • 组件耦合
    • GodotFileStorage依赖IStorage接口与ISerializer接口耦合度低便于替换实现。
    • 通过GodotPathExtensions识别Godot路径保持路径处理逻辑与业务解耦。
  • 外部依赖
    • Godot.FileAccess/DirAccess用于Godot虚拟路径的文件操作。
    • System.IO用于普通文件系统路径的文件操作。
    • Newtonsoft.JsonJsonSerializer的具体实现依赖。
  • 循环依赖
    • 未发现循环依赖;接口与实现分离清晰。
graph LR
GFS["GodotFileStorage"] --> IS["IStorage"]
GFS --> SER["ISerializer"]
GFS --> GPE["GodotPathExtensions"]
JS["JsonSerializer"] --> SER
GFS --> GD["Godot.FileAccess/DirAccess"]
GFS --> IO["System.IO"]

图表来源

章节来源

性能考量

  • 锁机制
    • 每个文件路径独立锁,减少锁竞争,提高并发性能。
    • 读写操作串行化,避免数据损坏。
  • 文件访问
    • Godot虚拟路径使用FileAccess/DirAccess适合资源与用户数据场景。
    • 普通路径使用标准.NET文件API支持完整文件系统访问。
  • 内存使用
    • 锁对象使用ConcurrentDictionary管理按需创建避免内存泄漏。
    • Delete完成后TryRemove移除锁防止字典无限增长。
  • 异步策略
    • ReadAsync/WriteAsync在锁范围内执行避免竞态异步主要用于避免阻塞UI线程。
  • 序列化开销
    • JSON可读性好调试友好二进制序列化器可显著降低体积与提升性能。

章节来源

故障排查指南

  • 常见异常
    • ArgumentException路径为空、包含“..”、无效键。
    • FileNotFoundException读取不存在的文件。
    • IOExceptionGodot路径删除失败或写入权限不足。
  • 排查步骤
    • 路径合法性:确认键不包含“..”且符合目标路径类型res://、user://或普通路径)。
    • 权限问题user://路径需确保Godot用户目录可写普通路径需检查磁盘权限。
    • 文件状态使用Exists检查文件是否存在不存在时使用默认值或初始化数据。
    • 锁竞争:避免在锁内执行长耗时操作;必要时拆分逻辑。
  • 示例场景
    • 读取存档失败捕获FileNotFoundException创建默认存档并写入。
    • 删除失败捕获IOException检查Godot错误码并记录日志。

章节来源

结论

GodotFileStorage通过明确的路径类型识别、严格的路径安全控制、细粒度的锁机制与ISerializer解耦为Godot应用提供了可靠、高性能的文件存储方案。其对res://、user://与普通路径的统一支持使开发者能够在不同场景下灵活选择存储位置异步API与序列化策略的可替换性进一步提升了系统的可维护性与性能潜力。遵循本文的最佳实践与故障排查建议可在复杂多线程环境下稳定地使用该存储系统。

附录

  • API参考来自接口定义
    • Exists/ExistsAsync检查键是否存在。
    • Read/Read/ReadAsync读取并反序列化对象。
    • Write/WriteAsync序列化并写入对象。
    • Delete删除文件GodotFileStorage已实现
  • 路径扩展
    • IsGodotPath/IsUserPath/IsResPath辅助判断路径类型。

章节来源