.Net_比对Json文件是否一致
简介
- 该方法用于比较两个Json文件是否完全一致,仅考虑内容
- 若两个文件中的内容只是顺序不一致,内容是一样的,那么也代表这两个文件是相等的
实现代码
- 调用
using CompareJsonFiles;
Console.WriteLine("================= 输入信息 ===================");
Console.WriteLine("请输入源Json文件路径:");
var sourcePath = Console.ReadLine();
Console.WriteLine($"{Environment.NewLine}请输入目标Json文件路径:");
var targetPath = Console.ReadLine();
Console.WriteLine($"{Environment.NewLine}您输入的源路径为:{sourcePath},目标路径为:{targetPath}");
Console.WriteLine($"================= 输入信息 =================== {Environment.NewLine}");
CompareJsonHelper.CompareJsonFiles(sourcePath?.Trim(), targetPath?.Trim());
- 实现
using Newtonsoft.Json.Linq;
namespace CompareJsonFiles;
/// <summary>
/// 比对Json文件的帮助类
/// </summary>
public static class CompareJsonHelper
{
/// <summary>
/// 比较两个JSON文件的内容
/// </summary>
/// <param name="sourcePath">源文件</param>
/// <param name="targetPath">目标文件</param>
public static void CompareJsonFiles(string? sourcePath, string? targetPath)
{
if (!IsExistForJsonFile(sourcePath, targetPath))
{
return;
}
// 加载并解析JSON文件
var json1 = JToken.Parse(File.ReadAllText(sourcePath));
var json2 = JToken.Parse(File.ReadAllText(targetPath));
// 标准化JSON结构
var normalizedSourceJson = NormalizeJson(json1);
var normalizedTargetJson = NormalizeJson(json2);
// 比较JSON内容
var differences = FindDifferences(normalizedSourceJson, normalizedTargetJson, string.Empty);
// 输出差异
if (differences.Count == 0)
{
Console.WriteLine("======================== 两个文件内容一致!==============================");
}
else
{
Console.WriteLine("============================= 两个文件存在以下差异:=================================");
foreach (var diff in differences)
{
Console.WriteLine(diff);
}
}
}
/// <summary>
/// 监测源文件和目标文件是不是Json文件
/// </summary>
/// <param name="sourcePath"></param>
/// <param name="targetPath"></param>
/// <returns></returns>
private static bool IsExistForJsonFile(string? sourcePath, string? targetPath)
{
if (string.IsNullOrWhiteSpace(sourcePath))
{
Console.WriteLine("错误信息:源文件路径不能为空");
return false;
}
if (string.IsNullOrWhiteSpace(targetPath))
{
Console.WriteLine("错误信息:目标文件路径不能为空");
return false;
}
if (!System.IO.File.Exists(sourcePath))
{
Console.WriteLine("错误信息:源文件不存在");
return false;
}
if (!System.IO.File.Exists(targetPath))
{
Console.WriteLine("错误信息:目标文件不存在");
return false;
}
if (Path.GetExtension(sourcePath) != ".json")
{
Console.WriteLine("错误信息:源文件不是Json文件");
return false;
}
if (Path.GetExtension(targetPath) != ".json")
{
Console.WriteLine("错误信息:目标文件不是Json文件");
return false;
}
return true;
}
/// <summary>
/// 标准化JSON结构以便比较
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
private static JToken NormalizeJson(JToken token)
{
switch (token.Type)
{
case JTokenType.Object:
var sortedObject = new JObject();
var properties = token.Children<JProperty>().ToList();
properties.Sort((x, y) => string.Compare(x.Name, y.Name, StringComparison.Ordinal));
foreach (var prop in properties)
{
sortedObject.Add(prop.Name, NormalizeJson(prop.Value));
}
return sortedObject;
case JTokenType.Array:
var sortedArray = new JArray(token.Select(NormalizeJson).OrderBy(t => t.ToString()));
return sortedArray;
default:
return token.DeepClone();
}
}
/// <summary>
/// 查找两个JSON之间的差异
/// </summary>
/// <param name="source"></param>
/// <param name="target"></param>
/// <param name="path"></param>
/// <returns></returns>
private static List<string> FindDifferences(JToken source, JToken target, string path)
{
var differences = new List<string>();
if (source.Type != target.Type)
{
differences.Add($"路径 {path} 类型不同: {source.Type} 和 {target.Type}");
return differences;
}
switch (source.Type)
{
case JTokenType.Object:
foreach (var property in ((JObject)source).Properties())
{
if (!((JObject)target).TryGetValue(property.Name, out JToken? tryTargetValue))
{
differences.Add($"路径 {path}.{property.Name} 在第二个文件中不存在");
continue;
}
differences.AddRange(FindDifferences(property.Value, tryTargetValue, $"{path}.{property.Name}"));
}
foreach (var property in ((JObject)target).Properties())
{
if (!((JObject)source).TryGetValue(property.Name, out _))
{
differences.Add($"路径 {path}.{property.Name} 在第一个文件中不存在");
}
}
break;
case JTokenType.Array:
var arraySource = source as JArray;
var arrayTarget = target as JArray;
for (var i = 0; i < Math.Max(arraySource?.Count ?? 0, arrayTarget?.Count ?? 0); i++)
{
if (i >= arraySource?.Count || i >= arrayTarget?.Count)
{
differences.Add($"路径 {path}[{i}] 数组长度不一致");
continue;
}
differences.AddRange(FindDifferences(arraySource![i], arrayTarget![i], $"{path}[{i}]"));
}
break;
default:
if (!JToken.DeepEquals(source, target))
{
differences.Add($"路径 {path} 值不同: {source} 和 {target}");
}
break;
}
return differences;
}
}