diff --git a/GFramework.Core.Abstractions/storage/IStorage.cs b/GFramework.Core.Abstractions/storage/IStorage.cs
new file mode 100644
index 0000000..a39105b
--- /dev/null
+++ b/GFramework.Core.Abstractions/storage/IStorage.cs
@@ -0,0 +1,72 @@
+using System.Threading.Tasks;
+using GFramework.Core.Abstractions.utility;
+
+namespace GFramework.Core.Abstractions.storage;
+
+///
+/// 存储接口,提供同步和异步的数据存储操作功能
+///
+public interface IStorage : IUtility
+{
+ ///
+ /// 检查指定键的存储项是否存在
+ ///
+ /// 要检查的键
+ /// 如果键存在则返回true,否则返回false
+ bool Exists(string key);
+
+ ///
+ /// 异步检查指定键的存储项是否存在
+ ///
+ /// 要检查的键
+ /// 如果键存在则返回true,否则返回false
+ Task ExistsAsync(string key);
+
+ ///
+ /// 读取指定键的值
+ ///
+ /// 要读取的值的类型
+ /// 要读取的键
+ /// 指定键对应的值
+ T Read(string key);
+
+ ///
+ /// 读取指定键的值,如果键不存在则返回默认值
+ ///
+ /// 要读取的值的类型
+ /// 要读取的键
+ /// 当键不存在时返回的默认值
+ /// 指定键对应的值,如果键不存在则返回默认值
+ T Read(string key, T defaultValue);
+
+ ///
+ /// 异步读取指定键的值
+ ///
+ /// 要读取的值的类型
+ /// 要读取的键
+ /// 指定键对应的值
+ Task ReadAsync(string key);
+
+ ///
+ /// 将值写入指定键
+ ///
+ /// 要写入的值的类型
+ /// 要写入的键
+ /// 要写入的值
+ void Write(string key, T value);
+
+ ///
+ /// 异步将值写入指定键
+ ///
+ /// 要写入的值的类型
+ /// 要写入的键
+ /// 要写入的值
+ /// 异步操作任务
+ Task WriteAsync(string key, T value);
+
+ ///
+ /// 删除指定键的存储项
+ ///
+ /// 要删除的键
+ void Delete(string key);
+}
\ No newline at end of file
diff --git a/GFramework.Game.Abstractions/serializer/ISerializer.cs b/GFramework.Game.Abstractions/serializer/ISerializer.cs
new file mode 100644
index 0000000..a38b556
--- /dev/null
+++ b/GFramework.Game.Abstractions/serializer/ISerializer.cs
@@ -0,0 +1,23 @@
+namespace GFramework.Game.Abstractions.serializer;
+
+///
+/// 定义序列化器接口,提供对象序列化和反序列化的通用方法
+///
+public interface ISerializer
+{
+ ///
+ /// 将指定的对象序列化为字符串
+ ///
+ /// 要序列化的对象类型
+ /// 要序列化的对象实例
+ /// 序列化后的字符串表示
+ string Serialize(T value);
+
+ ///
+ /// 将字符串数据反序列化为指定类型的对象
+ ///
+ /// 要反序列化的目标对象类型
+ /// 包含序列化数据的字符串
+ /// 反序列化后的对象实例
+ T Deserialize(string data);
+}
\ No newline at end of file
diff --git a/GFramework.Game/GFramework.Game.csproj b/GFramework.Game/GFramework.Game.csproj
index 9305dcc..13983d2 100644
--- a/GFramework.Game/GFramework.Game.csproj
+++ b/GFramework.Game/GFramework.Game.csproj
@@ -10,4 +10,7 @@
+
+
+
diff --git a/GFramework.Game/serializer/JsonSerializer.cs b/GFramework.Game/serializer/JsonSerializer.cs
new file mode 100644
index 0000000..fa4de37
--- /dev/null
+++ b/GFramework.Game/serializer/JsonSerializer.cs
@@ -0,0 +1,29 @@
+using GFramework.Game.Abstractions.serializer;
+using Newtonsoft.Json;
+
+namespace GFramework.Game.serializer;
+
+///
+/// JSON序列化器实现类,用于将对象序列化为JSON字符串或将JSON字符串反序列化为对象
+///
+public sealed class JsonSerializer : ISerializer
+{
+ ///
+ /// 将指定的对象序列化为JSON字符串
+ ///
+ /// 要序列化的对象类型
+ /// 要序列化的对象实例
+ /// 序列化后的JSON字符串
+ public string Serialize(T value)
+ => JsonConvert.SerializeObject(value);
+
+ ///
+ /// 将JSON字符串反序列化为指定类型的对象
+ ///
+ /// 要反序列化的对象类型
+ /// 包含JSON数据的字符串
+ /// 反序列化后的对象实例
+ /// 当无法反序列化数据时抛出
+ public T Deserialize(string data)
+ => JsonConvert.DeserializeObject(data) ?? throw new ArgumentException("Cannot deserialize data");
+}
\ No newline at end of file
diff --git a/GFramework.Game/storage/FileStorage.cs b/GFramework.Game/storage/FileStorage.cs
new file mode 100644
index 0000000..e5c1d63
--- /dev/null
+++ b/GFramework.Game/storage/FileStorage.cs
@@ -0,0 +1,170 @@
+using System.Text;
+using GFramework.Core.Abstractions.storage;
+using GFramework.Game.Abstractions.serializer;
+
+namespace GFramework.Game.storage;
+
+///
+/// 基于文件系统的存储实现,实现了IStorage接口
+///
+public sealed class FileStorage : IStorage
+{
+ private readonly string _extension;
+ private readonly string _rootPath;
+ private readonly ISerializer _serializer;
+
+ ///
+ /// 初始化FileStorage实例
+ ///
+ /// 存储根目录路径
+ /// 序列化器实例
+ /// 存储文件的扩展名
+ public FileStorage(string rootPath, ISerializer serializer, string extension = ".dat")
+ {
+ _rootPath = rootPath;
+ _serializer = serializer;
+ _extension = extension;
+
+ Directory.CreateDirectory(_rootPath);
+ }
+
+ #region Delete
+
+ ///
+ /// 删除指定键的存储项
+ ///
+ /// 存储键
+ public void Delete(string key)
+ {
+ var path = ToPath(key);
+ if (File.Exists(path))
+ File.Delete(path);
+ }
+
+ #endregion
+
+ #region Helpers
+
+ ///
+ /// 将存储键转换为文件路径
+ ///
+ /// 存储键
+ /// 对应的文件路径
+ private string ToPath(string key)
+ {
+ // 防止非法路径
+ key = Path.GetInvalidFileNameChars().Aggregate(key, (current, c) => current.Replace(c, '_'));
+ return Path.Combine(_rootPath, $"{key}{_extension}");
+ }
+
+ #endregion
+
+ #region Exists
+
+ ///
+ /// 检查指定键的存储项是否存在
+ ///
+ /// 存储键
+ /// 存在返回true,否则返回false
+ public bool Exists(string key)
+ => File.Exists(ToPath(key));
+
+ ///
+ /// 异步检查指定键的存储项是否存在
+ ///
+ /// 存储键
+ /// 存在返回true,否则返回false
+ public Task ExistsAsync(string key)
+ => Task.FromResult(Exists(key));
+
+ #endregion
+
+ #region Read
+
+ ///
+ /// 读取指定键的存储项
+ ///
+ /// 要反序列化的类型
+ /// 存储键
+ /// 反序列化后的对象
+ /// 当指定键不存在时抛出
+ public T Read(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(content);
+ }
+
+ ///
+ /// 读取指定键的存储项,如果不存在则返回默认值
+ ///
+ /// 要反序列化的类型
+ /// 存储键
+ /// 默认值
+ /// 存在则返回反序列化后的对象,否则返回默认值
+ public T Read(string key, T defaultValue)
+ {
+ var path = ToPath(key);
+ if (!File.Exists(path))
+ return defaultValue;
+
+ var content = File.ReadAllText(path, Encoding.UTF8);
+ return _serializer.Deserialize(content);
+ }
+
+ ///
+ /// 异步读取指定键的存储项
+ ///
+ /// 要反序列化的类型
+ /// 存储键
+ /// 反序列化后的对象
+ /// 当指定键不存在时抛出
+ public async Task ReadAsync(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(content);
+ }
+
+ #endregion
+
+ #region Write
+
+ ///
+ /// 写入指定键的存储项
+ ///
+ /// 要序列化的类型
+ /// 存储键
+ /// 要存储的值
+ public void Write(string key, T value)
+ {
+ var path = ToPath(key);
+ var content = _serializer.Serialize(value);
+
+ File.WriteAllText(path, content, Encoding.UTF8);
+ }
+
+ ///
+ /// 异步写入指定键的存储项
+ ///
+ /// 要序列化的类型
+ /// 存储键
+ /// 要存储的值
+ public async Task WriteAsync(string key, T value)
+ {
+ var path = ToPath(key);
+ var content = _serializer.Serialize(value);
+
+ await File.WriteAllTextAsync(path, content, Encoding.UTF8);
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/GFramework.Game/storage/ScopedStorage.cs b/GFramework.Game/storage/ScopedStorage.cs
new file mode 100644
index 0000000..ba85f19
--- /dev/null
+++ b/GFramework.Game/storage/ScopedStorage.cs
@@ -0,0 +1,98 @@
+using GFramework.Core.Abstractions.storage;
+
+namespace GFramework.Game.storage;
+
+///
+/// 提供带有作用域前缀的存储包装器,将所有键都加上指定的前缀
+///
+/// 内部的实际存储实现
+/// 用于所有键的前缀字符串
+public sealed class ScopedStorage(IStorage inner, string prefix) : IStorage
+{
+ ///
+ /// 检查指定键是否存在
+ ///
+ /// 要检查的键
+ /// 如果键存在则返回true,否则返回false
+ public bool Exists(string key)
+ => inner.Exists(Key(key));
+
+ ///
+ /// 异步检查指定键是否存在
+ ///
+ /// 要检查的键
+ /// 如果键存在则返回true,否则返回false
+ public Task ExistsAsync(string key)
+ => inner.ExistsAsync(Key(key));
+
+ ///
+ /// 读取指定键的值
+ ///
+ /// 要读取的值的类型
+ /// 要读取的键
+ /// 键对应的值
+ public T Read(string key)
+ => inner.Read(Key(key));
+
+ ///
+ /// 读取指定键的值,如果键不存在则返回默认值
+ ///
+ /// 要读取的值的类型
+ /// 要读取的键
+ /// 当键不存在时返回的默认值
+ /// 键对应的值或默认值
+ public T Read(string key, T defaultValue)
+ => inner.Read(Key(key), defaultValue);
+
+ ///
+ /// 异步读取指定键的值
+ ///
+ /// 要读取的值的类型
+ /// 要读取的键
+ /// 键对应的值的任务
+ public Task ReadAsync(string key)
+ => inner.ReadAsync(Key(key));
+
+ ///
+ /// 写入指定键值对
+ ///
+ /// 要写入的值的类型
+ /// 要写入的键
+ /// 要写入的值
+ public void Write(string key, T value)
+ => inner.Write(Key(key), value);
+
+ ///
+ /// 异步写入指定键值对
+ ///
+ /// 要写入的值的类型
+ /// 要写入的键
+ /// 要写入的值
+ public Task WriteAsync(string key, T value)
+ => inner.WriteAsync(Key(key), value);
+
+ ///
+ /// 删除指定键
+ ///
+ /// 要删除的键
+ public void Delete(string key)
+ => inner.Delete(Key(key));
+
+ ///
+ /// 为给定的键添加前缀
+ ///
+ /// 原始键
+ /// 添加前缀后的键
+ private string Key(string key)
+ => string.IsNullOrEmpty(prefix)
+ ? key
+ : $"{prefix}/{key}";
+
+ ///
+ /// 创建一个新的作用域存储实例
+ ///
+ /// 新的作用域名称
+ /// 新的作用域存储实例
+ public IStorage Scope(string scope)
+ => new ScopedStorage(inner, Key(scope));
+}
\ No newline at end of file