GFramework/docs/zh-CN/godot/storage.md
GeWuYou 1ab615db26 docs(source-generators): 更新文档结构并调整Godot版本信息
- 将Source Generators概述文档从overview重命名为index
- 更新所有相关文档中的链接指向新的index文件
- 移除Godot文档中的许可证和版本信息冗余内容
- 统一Godot版本要求从4.5.1+到4.6
- 删除各模块文档末尾的相关链接部分
- 优化文档结构提升可读性
2026-02-11 15:57:40 +08:00

275 lines
6.2 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.

# 存储模块 (Storage Module)
## 概述
存储模块是 GFramework.Godot 的核心存储实现,专门为 Godot 引擎设计的文件存储系统。该模块支持 Godot 的虚拟路径系统(如
`res://``user://`),并提供了按键级别的细粒度锁机制来保证线程安全。
## 核心类
### GodotFileStorage
Godot 特化的文件存储实现,实现了 `IStorage` 接口。
**主要特性:**
- ✅ Godot 虚拟路径支持(`res://`, `user://`
- ✅ 线程安全(按键级别的细粒度锁)
- ✅ 同步/异步读写操作
- ✅ 自动创建目录结构
- ❌ 删除操作Delete 方法未实现)
## 功能特性
### 路径处理
该存储系统支持三种路径类型:
#### 1. Godot 资源路径 (`res://`)
- **用途**:存储游戏资源文件
- **特点**:只读,包含在游戏构建中
- **示例**`res://config/game_settings.json`
#### 2. Godot 用户数据路径 (`user://`)
- **用途**:存储用户数据、存档、配置等
- **特点**:可读写,游戏可访问的用户目录
- **示例**`user://saves/save_001.dat`
#### 3. 普通文件系统路径
- **用途**:存储临时文件或调试数据
- **特点**:完整的文件系统访问
- **示例**`C:/Games/MyGame/logs/debug.log`
### 路径验证与清理
```mermaid
graph TD
A[输入路径] --> B{包含 ".." ?}
B -->|是| C[抛出异常]
B -->|否| D{是 Godot 路径?}
D -->|是| E[直接使用]
D -->|否| F[清理路径段]
F --> G[替换无效字符]
G --> H[创建目录结构]
H --> I[返回绝对路径]
C --> J[结束]
E --> J
I --> J
```
### 线程安全机制
每个文件路径都有独立的锁对象,确保:
1. **细粒度锁** - 不同文件可以并发访问
2. **避免死锁** - 锁的获取顺序一致
3. **高性能** - 减少锁竞争
## API 接口
### IStorage 接口
```csharp
public interface IStorage
{
// 读取操作
T Read<T>(string key);
T Read<T>(string key, T defaultValue);
Task<T> ReadAsync<T>(string key);
// 写入操作
void Write<T>(string key, T value);
Task WriteAsync<T>(string key, T value);
// 检查存在性
bool Exists(string key);
Task<bool> ExistsAsync(string key);
// 删除操作(未实现)
void Delete(string key);
}
```
## 使用示例
### 基本使用
```csharp
// 创建存储实例(需要序列化器)
var serializer = new JsonSerializer(); // 或其他序列化器
var storage = new GodotFileStorage(serializer);
// 写入用户数据
var userData = new UserData
{
PlayerName = "Alice",
Level = 5,
Score = 1000
};
storage.Write("user://player.dat", userData);
// 读取用户数据
var loadedData = storage.Read<UserData>("user://player.dat");
Console.WriteLine($"Player: {loadedData.PlayerName}, Level: {loadedData.Level}");
```
### 异步操作
```csharp
// 异步写入游戏配置
var config = new GameConfig
{
Resolution = "1920x1080",
Fullscreen = true,
Volume = 0.8f
};
await storage.WriteAsync("user://config.json", config);
// 异步读取配置
var loadedConfig = await storage.ReadAsync<GameConfig>("user://config.json");
```
### 不同路径类型使用
```csharp
// 读取游戏资源(只读)
var levelData = storage.Read<LevelData>("res://levels/level_001.json");
// 存储用户存档
var saveData = new SaveData { /* ... */ };
storage.Write("user://saves/slot_001.dat", saveData);
// 存储调试信息(普通路径)
var debugLog = new DebugLog { /* ... */ };
storage.Write("logs/debug_" + DateTime.Now.Ticks + ".json", debugLog);
```
### 存在性检查
```csharp
// 检查文件是否存在
if (storage.Exists("user://settings.json"))
{
var settings = storage.Read<AppSettings>("user://settings.json");
// 使用设置...
}
else
{
// 使用默认设置
var defaultSettings = new AppSettings();
storage.Write("user://settings.json", defaultSettings);
}
```
### 带默认值的读取
```csharp
// 尝试读取,如果文件不存在则返回默认值
var settings = storage.Read("user://user_prefs.json", new UserPrefs
{
Language = "en",
Volume = 1.0f,
Difficulty = 1
});
```
## 路径扩展
该模块使用了路径扩展方法:
```csharp
public static class GodotPathExtensions
{
public static bool IsUserPath(this string path);
public static bool IsResPath(this string path);
public static bool IsGodotPath(this string path);
}
```
**使用示例:**
```csharp
string path1 = "user://save.dat";
string path2 = "res://config.json";
string path3 = "C:/temp/file.txt";
Console.WriteLine(path1.IsGodotPath()); // true
Console.WriteLine(path1.IsUserPath()); // true
Console.WriteLine(path2.IsResPath()); // true
Console.WriteLine(path3.IsGodotPath()); // false
```
## 性能考虑
### 1. 锁机制
- 每个文件路径独立锁,减少锁竞争
- 读写操作串行化,避免数据损坏
### 2. 文件访问
- Godot 虚拟路径使用 `FileAccess` API
- 普通路径使用标准 .NET 文件 I/O
- 自动创建目录结构
### 3. 内存使用
- 锁对象使用 `ConcurrentDictionary` 管理
- 锁对象按需创建,避免内存泄漏
## 错误处理
### 常见异常
1. **ArgumentException** - 路径参数无效
- 空路径
- 包含 ".." 的路径
- 无效的存储键
2. **FileNotFoundException** - 文件不存在
- 读取不存在的文件时抛出
3. **IOException** - 文件操作失败
- 写入权限不足
- 磁盘空间不足
### 错误处理示例
```csharp
try
{
var data = storage.Read<UserData>("user://save.dat");
}
catch (FileNotFoundException)
{
Console.WriteLine("存档文件不存在,创建新的存档");
var newSave = new UserData();
storage.Write("user://save.dat", newSave);
}
catch (Exception ex)
{
Console.WriteLine($"读取存档失败: {ex.Message}");
}
```
## 最佳实践
1. **路径选择**
- 游戏资源使用 `res://`
- 用户数据使用 `user://`
- 调试/临时文件使用普通路径
2. **异常处理**
- 总是处理 `FileNotFoundException`
- 使用带默认值的 `Read` 重载方法
3. **性能优化**
- 批量读写时使用异步方法
- 避免频繁的小文件操作
4. **序列化器选择**
- JSON人类可读调试友好
- 二进制:性能更好,文件更小