SimpleKeyValueStore.cs

using System.Collections.Concurrent;
using System.Text.Json;
namespace MiniRedis
{
public class SimpleKeyValueStore : IDisposable
{
private readonly ConcurrentDictionary<string, object> data;
private readonly string filePath;
private readonly object fileLock = new object();
private readonly JsonSerializerOptions jsonOptions;
public SimpleKeyValueStore(string filePath = "data.json")
{
this.filePath = filePath;
data = new ConcurrentDictionary<string, object>();
// 配置 JSON 序列化选项
jsonOptions = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNameCaseInsensitive = true,
Converters = { new JsonElementConverter() } // 添加自定义转换器
};
// 从磁盘加载现有数据
LoadFromDisk();
}
// 设置键值对
public void Set<T>(string key, T value)
{
data[key] = value;
PersistToDisk(); // 立即持久化到磁盘
}
// 获取值
public T Get<T>(string key)
{
if (data.TryGetValue(key, out object value))
{
// 如果值是 JsonElement,需要转换为目标类型
if (value is JsonElement jsonElement)
{
return jsonElement.Deserialize<T>(jsonOptions);
}
return (T)value;
}
return default(T);
}
// 检查键是否存在
public bool ContainsKey(string key)
{
return data.ContainsKey(key);
}
// 删除键
public bool Remove(string key)
{
var result = data.TryRemove(key, out _);
if (result) PersistToDisk(); // 如果删除成功,立即持久化到磁盘
return result;
}
// 获取所有键
public ICollection<string> Keys()
{
return data.Keys;
}
// 从磁盘加载数据
private void LoadFromDisk()
{
if (!File.Exists(filePath)) return;
try
{
lock (fileLock)
{
var json = File.ReadAllText(filePath);
var deserialized = JsonSerializer.Deserialize<ConcurrentDictionary<string, object>>(json, jsonOptions);
if (deserialized != null)
{
foreach (var kvp in deserialized)
{
data[kvp.Key] = kvp.Value;
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error loading data from disk: {ex.Message}");
}
}
// 持久化到磁盘
private void PersistToDisk()
{
try
{
lock (fileLock)
{
var json = JsonSerializer.Serialize(data, jsonOptions);
// 先写入临时文件,然后替换原文件,确保数据一致性
var tempPath = filePath + ".tmp";
File.WriteAllText(tempPath, json);
// 替换文件
if (File.Exists(filePath))
File.Replace(tempPath, filePath, null);
else
File.Move(tempPath, filePath);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error persisting data to disk: {ex.Message}");
}
}
// 清理资源
public void Dispose()
{
// 确保所有更改都已保存
PersistToDisk();
}
}
// 自定义 JSON 转换器,处理 JsonElement 到具体类型的转换
public class JsonElementConverter : System.Text.Json.Serialization.JsonConverter<object>
{
public override object Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
using (JsonDocument document = JsonDocument.ParseValue(ref reader))
{
return ConvertJsonElement(document.RootElement);
}
}
private object ConvertJsonElement(JsonElement element)
{
switch (element.ValueKind)
{
case JsonValueKind.String:
return element.GetString();
case JsonValueKind.Number:
if (element.TryGetInt32(out int intValue))
return intValue;
if (element.TryGetInt64(out long longValue))
return longValue;
return element.GetDouble();
case JsonValueKind.True:
return true;
case JsonValueKind.False:
return false;
case JsonValueKind.Array:
var array = new object[element.GetArrayLength()];
int index = 0;
foreach (JsonElement arrayElement in element.EnumerateArray())
{
array[index++] = ConvertJsonElement(arrayElement);
}
return array;
case JsonValueKind.Object:
var dict = new System.Collections.Generic.Dictionary<string, object>();
foreach (var property in element.EnumerateObject())
{
dict[property.Name] = ConvertJsonElement(property.Value);
}
return dict;
default:
return null;
}
}
public override void Write(
Utf8JsonWriter writer,
object value,
JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}
}

Program.cs

namespace MiniRedis
{
class Program
{
static void Main(string[] args)
{
// 创建存储实例
using var store = new SimpleKeyValueStore("mydata.json");
Console.WriteLine($"Name:{store.Get<string>("name")}");
// 存储数据
store.Set("name", "John Doe");
store.Set("age", 30);
store.Set("scores", new[] { 90, 85, 95 });
// 检索数据
var name = store.Get<string>("name");
var age = store.Get<int>("age");
var scores = store.Get<int[]>("scores");
Console.WriteLine($"Name: {name}");
Console.WriteLine($"Age: {age}");
Console.WriteLine($"Scores: {string.Join(", ", scores)}");
// 检查键是否存在
if (store.ContainsKey("name")) Console.WriteLine("Key 'name' exists");
// 删除键
store.Remove("age");
// 获取所有键
var keys = store.Keys();
Console.WriteLine($"All keys: {string.Join(", ", keys)}");
}
}
}

