C# 中的 JSON 数据存储、读取和合并操作

在博客中,我将介绍一个名为JsonFileManager的类,该类用于管理数据的保存和读取操作,并提供了一些数据合并的方法。下面是该类的代码及其功能的详细说明。

引用和命名空间

1
2
3
4
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;

上述代码段中的using语句用于引入所需的命名空间,以便在代码中使用相关的类型和方法。

命名空间

1
2
3
4
5
6
7
namespace Demo
{
public static class JsonFileManager
{
// ...
}
}

在该命名空间中,定义了一个名为JsonFileManager的静态类,用于提供数据保存和读取的功能。

常量和文件路径

1
2
3
4
5
6
private const string BACKUP_DIRECTORY = @"C:\json_backup\";
public const string INBOUND_FILE_NAME = "Inbound.json";
public const string OUTBOUND_FILE_NAME = "OutBound.json";
public const string CUSTOMER_FILE_NAME = "Customer.json";
public const string MATERIAL_FILE_NAME = "Material.json";
public const string SUPPLIER_FILE_NAME = "Supplier.json";

这些常量定义了备份目录的路径和各个数据文件的文件名。

SaveData 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void SaveData<T>(List<T> data, string filename)
{
// 检查备份目录是否存在,如果不存在则创建
if (!Directory.Exists(BACKUP_DIRECTORY))
Directory.CreateDirectory(BACKUP_DIRECTORY);

// 生成文件路径
string filePath = Path.Combine(BACKUP_DIRECTORY, filename);

// 读取已保存的数据
List<T> existingData = ReadData<T>(filename);

// 合并数据,去除重复项
List<T> newData = MergeData(existingData, data);

// 将数据序列化为 JSON 字符串
string json = JsonConvert.SerializeObject(newData, Formatting.Indented);

// 保存 JSON 字符串到文件
File.WriteAllText(filePath, json);
}

该方法用于保存数据到指定的文件。它接收一个泛型参数T表示数据类型,一个List<T>类型的data参数表示要保存的数据列表,以及一个string类型的filename参数表示文件名。方法的实现逻辑如下:

  1. 检查备份目录是否存在,如果不存在则创建备份目录。
  2. 生成文件路径。
  3. 调用ReadData<T>方法读取已保存的数据。
  4. 调用MergeData方法合并已保存的数据和新数据,去除重复项。
  5. 使用JsonConvert.SerializeObject方法将数据序列化为 JSON 字符串。
  6. 调用File.WriteAllText方法将 JSON 字符串写入文件。

ReadData 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static List<T> ReadData<T>(string filename)
{
// 生成文件路径
string filePath = Path.Combine(BACKUP_DIRECTORY, filename);

// 检查文件是否存在
if (!File.Exists(filePath))
return new List<T>();

// 读取文件内容
string json = File.ReadAllText(filePath);

// 反序列化 JSON 字符串为数据对象
List<T> data = JsonConvert.DeserializeObject<List<T>>(json);

return data ?? new List<T>();
}

该方法用于读取指定文件中的数据,并以List<T>类型的列表形式返回。它接收一个string类型的filename参数表示要读取的文件名。方法的实现逻辑如下:

  1. 生成文件路径。
  2. 检查文件是否存在,如果文件不存在则返回空的数据列表。
  3. 读取文件内容。
  4. 使用JsonConvert.DeserializeObject方法将 JSON 字符串反序列化为数据对象。
  5. 返回反序列化后的数据列表。

MergeData 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static List<T> MergeData<T>(List<T> existingData, List<T> newData)
{
// 获取属性名用于去重判断
string propertyName = GetPropertyName<T>();

// 去除重复项
HashSet<string> existingSet = new HashSet<string>();
foreach (var item in existingData)
{
var propertyValue = GetPropertyValue(item, propertyName);
if (propertyValue != null)
{
existingSet.Add(propertyValue.ToString());
}
}

List<T> mergedData = new List<T>(existingData);
foreach (var item in newData)
{
var propertyValue = GetPropertyValue(item, propertyName);
if (propertyValue != null && !existingSet.Contains(propertyValue.ToString()))
{
mergedData.Add(item);
existingSet.Add(propertyValue.ToString());
}
}

return mergedData;
}

该方法用于合并已保存的数据和新数据,并去除重复项。它接收两个List<T>类型的参数existingDatanewData,表示已保存的数据和新数据。方法的实现逻辑如下:

  1. 获取用于去重判断的属性名,调用GetPropertyName<T>方法获取属性名。
  2. 创建一个HashSet<string>类型的集合existingSet,用于存储已保存数据中的属性值。
  3. 遍历已保存数据列表existingData,获取每个数据项的属性值,并将属性值转换为字符串类型后添加到existingSet集合中。
  4. 创建一个新的数据列表mergedData,初始值为已保存的数据列表existingData的副本。
  5. 遍历新数据列表newData,获取每个数据项的属性值,并判断属性值是否为空以及existingSet集合是否包含该属性值的字符串形式。
  6. 如果属性值不为空且existingSet集合中不包含该属性值的字符串形式,则将数据项添加到mergedData列表中,并将属性值的字符串形式添加到existingSet集合中。
  7. 返回合并后的数据列表mergedData

MergeDataWithLocal 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public static List<T> MergeDataWithLocal<T>(List<T> newData, string filename)
{
// 读取本地的数据
List<T> existingData= ReadData<T>(filename);

// 获取属性名用于查找本地数据
string propertyName = GetPropertyName<T>();

// 创建字典映射
Dictionary<string, T> existingDataMap = new Dictionary<string, T>();

// 填充字典映射
foreach (var item in existingData)
{
var propertyValue = GetPropertyValue(item, propertyName);
if (propertyValue != null)
{
string key = propertyValue.ToString();
if (!existingDataMap.ContainsKey(key))
{
existingDataMap.Add(key, item);
}
}
}

// 替换newData中的项
for (int i = 0; i < newData.Count; i++)
{
var itemToReplace = newData[i];
var propertyValue = GetPropertyValue(itemToReplace, propertyName);
if (propertyValue != null)
{
string key = propertyValue.ToString();
if (existingDataMap.ContainsKey(key))
{
newData[i] = existingDataMap[key];
}
}
}

return newData;
}

该方法用于将新数据与本地数据进行合并。它接收一个List<T>类型的参数newData,表示新数据列表,以及一个string类型的filename参数,表示本地数据的文件名。方法的实现逻辑如下:

  1. 调用ReadData<T>方法读取本地数据,将结果保存在existingData变量中。
  2. 获取用于查找本地数据的属性名,调用GetPropertyName<T>方法获取属性名。
  3. 创建一个Dictionary<string, T>类型的字典existingDataMap,用于存储本地数据的映射关系。
  4. 遍历本地数据列表existingData,获取每个数据项的属性值,并将属性值转换为字符串类型后作为字典的键,数据项作为字典的值。
  5. 创建一个循环,遍历新数据列表newData中的每个数据项。
  6. 获取当前要替换的数据项itemToReplace的属性值,并将属性值转换为字符串类型后作为字典的键。
  7. 如果字典existingDataMap中包含该键,则从字典中获取对应的本地数据项,并将其替换为新数据列表newData中的对应项。
  8. 返回合并后的新数据列表newData

GetPropertyName 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static string GetPropertyName<T>()
{
Type type = typeof(T);

if (type == typeof(Repertory))
{
return "RepertoryId";
}
else if (type == typeof(Customer))
{
return "CustomerId";
}
else if (type == typeof(Item))
{
return "ItmId";
}
else if (type == typeof(Supplier))
{
return "SupplierId";
}

throw new Exception(type + "类型不匹配");
}

该方法用于根据数据类型T获取属性名。它根据不同的数据类型返回相应的属性名字符串。如果数据类型不匹配,则抛出异常。目前支持的数据类型包括RepertoryCustomerItemSupplier, 请根据自己需要修改数据类型。

GetPropertyValue 方法

1
2
3
4
5
6
7
8
9
10
11
private static object GetPropertyValue<T>(T item, string propertyName)
{
// 根据属性名获取属性值
var property = typeof(T).GetProperty(propertyName);
if (property != null)
{
return property.GetValue(item);
}

throw new Exception("获取不到" + propertyName + "属性值");
}

该方法用于根据属性名获取数据项中的属性值。它接收一个数据项item和属性名字符串propertyName作为参数。方法的实现逻辑如下:

  1. 根据数据项的类型T和属性名字符串propertyName获取属性对象。
  2. 如果属性对象不为空,则通过GetValue方法获取属性值,并返回属性值。
  3. 如果属性对象为空,则抛出异常,表示无法获取属性值。

以上就是JsonFileManager类的主要方法及其功能的说明。该类提供了数据的保存、读取和合并功能,可以方便地进行数据管理和操作。


C# 中的 JSON 数据存储、读取和合并操作
http://www.loquy.cn/posts/6f32793d.html
作者
loquy
发布于
2023年7月7日
许可协议