C#简易KV存储

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)}"); 
        }
    }
}
相关推荐
listhi5207 小时前
C# 操作 Excel
c#·excel·mfc
甄天7 小时前
VisionProC#联合编程相机实战开发
开发语言·数码相机·c#·机器视觉
c#上位机8 小时前
wpf之WrapPanel
c#·wpf
zimoyin9 小时前
C# FlaUI win 自动化框架,介绍
microsoft·c#·自动化
c#上位机9 小时前
wpf之StackPanel
c#·wpf
钢铁男儿9 小时前
【C#实战】使用ListBox控件与生成器模式构建灵活多变的金融资产管理系统
开发语言·c#
刘祯昊10 小时前
中望CAD二次开发(一)——开发环境配置
后端·c#
青鱼入云12 小时前
【面试场景题】不使用redis、zk如何自己开发一个分布式锁
redis·分布式·面试
txwtech13 小时前
第9篇c#调用c++动态库报错处理
开发语言·c#