GwWuYou c3376bf4d5 feat(storage): 添加存储系统接口和文件存储实现
- 定义了IStorage接口提供同步和异步的数据存储操作功能
- 实现了基于文件系统的FileStorage类支持读写删除操作
- 添加了ScopedStorage包装器为存储键提供作用域前缀功能
- 创建了ISerializer接口并实现JsonSerializer使用Newtonsoft.Json
- 在项目中引入Newtonsoft.Json包依赖
2026-01-11 19:56:31 +08:00

170 lines
5.0 KiB
C#
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.

using System.Text;
using GFramework.Core.Abstractions.storage;
using GFramework.Game.Abstractions.serializer;
namespace GFramework.Game.storage;
/// <summary>
/// 基于文件系统的存储实现实现了IStorage接口
/// </summary>
public sealed class FileStorage : IStorage
{
private readonly string _extension;
private readonly string _rootPath;
private readonly ISerializer _serializer;
/// <summary>
/// 初始化FileStorage实例
/// </summary>
/// <param name="rootPath">存储根目录路径</param>
/// <param name="serializer">序列化器实例</param>
/// <param name="extension">存储文件的扩展名</param>
public FileStorage(string rootPath, ISerializer serializer, string extension = ".dat")
{
_rootPath = rootPath;
_serializer = serializer;
_extension = extension;
Directory.CreateDirectory(_rootPath);
}
#region Delete
/// <summary>
/// 删除指定键的存储项
/// </summary>
/// <param name="key">存储键</param>
public void Delete(string key)
{
var path = ToPath(key);
if (File.Exists(path))
File.Delete(path);
}
#endregion
#region Helpers
/// <summary>
/// 将存储键转换为文件路径
/// </summary>
/// <param name="key">存储键</param>
/// <returns>对应的文件路径</returns>
private string ToPath(string key)
{
// 防止非法路径
key = Path.GetInvalidFileNameChars().Aggregate(key, (current, c) => current.Replace(c, '_'));
return Path.Combine(_rootPath, $"{key}{_extension}");
}
#endregion
#region Exists
/// <summary>
/// 检查指定键的存储项是否存在
/// </summary>
/// <param name="key">存储键</param>
/// <returns>存在返回true否则返回false</returns>
public bool Exists(string key)
=> File.Exists(ToPath(key));
/// <summary>
/// 异步检查指定键的存储项是否存在
/// </summary>
/// <param name="key">存储键</param>
/// <returns>存在返回true否则返回false</returns>
public Task<bool> ExistsAsync(string key)
=> Task.FromResult(Exists(key));
#endregion
#region Read
/// <summary>
/// 读取指定键的存储项
/// </summary>
/// <typeparam name="T">要反序列化的类型</typeparam>
/// <param name="key">存储键</param>
/// <returns>反序列化后的对象</returns>
/// <exception cref="FileNotFoundException">当指定键不存在时抛出</exception>
public T Read<T>(string key)
{
var path = ToPath(key);
if (!File.Exists(path))
throw new FileNotFoundException($"Storage key not found: {key}", path);
var content = File.ReadAllText(path, Encoding.UTF8);
return _serializer.Deserialize<T>(content);
}
/// <summary>
/// 读取指定键的存储项,如果不存在则返回默认值
/// </summary>
/// <typeparam name="T">要反序列化的类型</typeparam>
/// <param name="key">存储键</param>
/// <param name="defaultValue">默认值</param>
/// <returns>存在则返回反序列化后的对象,否则返回默认值</returns>
public T Read<T>(string key, T defaultValue)
{
var path = ToPath(key);
if (!File.Exists(path))
return defaultValue;
var content = File.ReadAllText(path, Encoding.UTF8);
return _serializer.Deserialize<T>(content);
}
/// <summary>
/// 异步读取指定键的存储项
/// </summary>
/// <typeparam name="T">要反序列化的类型</typeparam>
/// <param name="key">存储键</param>
/// <returns>反序列化后的对象</returns>
/// <exception cref="FileNotFoundException">当指定键不存在时抛出</exception>
public async Task<T> ReadAsync<T>(string key)
{
var path = ToPath(key);
if (!File.Exists(path))
throw new FileNotFoundException($"Storage key not found: {key}", path);
var content = await File.ReadAllTextAsync(path, Encoding.UTF8);
return _serializer.Deserialize<T>(content);
}
#endregion
#region Write
/// <summary>
/// 写入指定键的存储项
/// </summary>
/// <typeparam name="T">要序列化的类型</typeparam>
/// <param name="key">存储键</param>
/// <param name="value">要存储的值</param>
public void Write<T>(string key, T value)
{
var path = ToPath(key);
var content = _serializer.Serialize(value);
File.WriteAllText(path, content, Encoding.UTF8);
}
/// <summary>
/// 异步写入指定键的存储项
/// </summary>
/// <typeparam name="T">要序列化的类型</typeparam>
/// <param name="key">存储键</param>
/// <param name="value">要存储的值</param>
public async Task WriteAsync<T>(string key, T value)
{
var path = ToPath(key);
var content = _serializer.Serialize(value);
await File.WriteAllTextAsync(path, content, Encoding.UTF8);
}
#endregion
}