-
JSON序列化/反序列化——用C#演示用户数据持久化
第一部分:C#基础入门
实例13:JSON序列化/反序列化——用户数据持久化
实例介绍
JSON(JavaScript Object Notation) 是一种轻量级、易读易写的文本数据格式,广泛用于数据交换和持久化。序列化是将对象转换为JSON字符串的过程,反序列化则是反向操作——从JSON字符串恢复为对象。
在实际开发中,用户数据持久化是常见场景:比如将用户信息(姓名、邮箱、注册时间等)保存到本地JSON文件,程序下次启动时再读取这些数据,避免每次重新输入。本实例通过System.Text.Json(.NET官方JSON库)实现用户数据的序列化/反序列化,带你掌握JSON操作的核心逻辑,理解持久化的本质。
需求分析
1.定义用户模型:User类包含Id(用户ID)、Name(姓名)、Email(邮箱)、RegistrationTime(注册时间)四个属性;
2.序列化功能:将单个用户对象或用户列表转换为JSON字符串,保存到本地文件;
3.反序列化功能:从JSON文件读取字符串,恢复为用户对象或列表;
4.异常处理:处理文件不存在、JSON格式错误、文件权限不足等异常;
5.测试场景:
1.保存多个用户到users.json文件;
2.从文件读取用户列表,验证数据一致性;
3.模拟JSON格式错误(手动修改文件内容),测试异常捕获。
代码实现
csharp
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
namespace JsonPersistenceDemo
{
// ==================== 1. 用户模型类 ====================
public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty; // 初始化避免null
public string Email { get; set; } = string.Empty;
public DateTime RegistrationTime { get; set; }
}
// ==================== 2. 数据持久化工具类 ====================
public static class UserPersistence
{
// 序列化选项:缩进格式、自定义日期格式、允许中文
private static readonly JsonSerializerOptions _serializerOptions = new()
{
WriteIndented = true, // 缩进输出(易读)
DateFormatString = "yyyy-MM-dd HH:mm:ss", // 日期格式
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 允许中文等特殊字符
};
/// <summary>
/// 将对象序列化到JSON文件
/// </summary>
public static void SerializeToFile<T>(string filePath, T data)
{
try
{
// 1. 将对象转为JSON字符串
string jsonString = JsonSerializer.Serialize(data, _serializerOptions);
// 2. 写入文件(覆盖模式)
File.WriteAllText(filePath, jsonString, Encoding.UTF8);
Console.WriteLine($"✅ 数据已保存到:{filePath}");
}
catch (IOException ex)
{
Console.WriteLine($"❌ 序列化失败(文件操作错误):{ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"❌ 序列化失败:{ex.Message}");
}
}
/// <summary>
/// 从JSON文件反序列化为对象
/// </summary>
public static T? DeserializeFromFile<T>(string filePath)
{
try
{
// 1. 检查文件是否存在
if (!File.Exists(filePath))
{
Console.WriteLine($"❌ 文件不存在:{filePath}");
return default;
}
// 2. 读取文件内容
string jsonString = File.ReadAllText(filePath, Encoding.UTF8);
// 3. 转换为对象
return JsonSerializer.Deserialize<T>(jsonString, _serializerOptions);
}
catch (JsonException ex)
{
Console.WriteLine($"❌ 反序列化失败(JSON格式错误):{ex.Message}");
return default;
}
catch (IOException ex)
{
Console.WriteLine($"❌ 反序列化失败(文件操作错误):{ex.Message}");
return default;
}
catch (Exception ex)
{
Console.WriteLine($"❌ 反序列化失败:{ex.Message}");
return default;
}
}
}
// ==================== 3. 测试程序 ====================
class Program
{
static void Main(string[] args)
{
string filePath = "users.json";
// 步骤1:创建测试用户列表
var testUsers = new List<User>
{
new() { Id = 1, Name = "张三", Email = "zhangsan@example.com", RegistrationTime = DateTime.Now },
new() { Id = 2, Name = "李四", Email = "lisi@example.com", RegistrationTime = DateTime.Now.AddDays(-1) },
new() { Id = 3, Name = "王五", Email = "wangwu@example.com", RegistrationTime = DateTime.Now.AddMonths(-1) }
};
// 步骤2:序列化到文件
Console.WriteLine("=== 开始序列化 ===");
UserPersistence.SerializeToFile(filePath, testUsers);
// 步骤3:反序列化从文件
Console.WriteLine("
=== 开始反序列化 ===");
var loadedUsers = UserPersistence.DeserializeFromFile<List<User>>(filePath);
// 步骤4:验证结果
if (loadedUsers != null && loadedUsers.Count > 0)
{
Console.WriteLine("
=== 反序列化结果 ===");
foreach (var user in loadedUsers)
{
Console.WriteLine($"ID:{user.Id} | 姓名:{user.Name} | 邮箱:{user.Email} | 注册时间:{user.RegistrationTime}");
}
}
else
{
Console.WriteLine("
❌ 未读取到有效用户数据");
}
}
}
}
逐行讲解
-
用户模型类(User)
csharp
public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public DateTime RegistrationTime { get; set; }
}
属性设计:包含用户核心信息,string类型初始化= string.Empty避免序列化时出现null(可通过配置选项控制是否忽略null);
无参构造函数:System.Text.Json默认要求类有公共无参构造函数(本类使用C# 9+的记录类简化语法,编译器自动生成无参构造)。
2. 数据持久化工具类(UserPersistence)
序列化选项(_serializerOptions):
csharp
private static readonly JsonSerializerOptions _serializerOptions = new()
{
WriteIndented = true, // 缩进格式(JSON更易读)
DateFormatString = "yyyy-MM-dd HH:mm:ss", // 自定义日期格式
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 允许中文/特殊字符(避免转义为Unicode)
};
WriteIndented:默认false(紧凑格式),设为true后JSON会按层级缩进;
DateFormatString:默认是ISO 8601格式(如2025-12-15T14:30:00),自定义为更直观的yyyy-MM-dd HH:mm:ss;
Encoder:默认会转义非ASCII字符(如中文变为u5F20u4E09),UnsafeRelaxedJsonEscaping可保留原始字符。
SerializeToFile方法:
csharp
public static void SerializeToFile<T>(string filePath, T data)
{
string jsonString = JsonSerializer.Serialize(data, _serializerOptions); // 对象转JSON
File.WriteAllText(filePath, jsonString, Encoding.UTF8); // 写入文件
}
泛型
File.WriteAllText:覆盖写入文件(若需追加,需手动读取原有内容合并后再写入)。
DeserializeFromFile方法:
csharp
public static T? DeserializeFromFile<T>(string filePath)
{
if (!File.Exists(filePath)) return default; // 文件不存在返回默认值
string jsonString = File.ReadAllText(filePath, Encoding.UTF8); // 读文件
return JsonSerializer.Deserialize<T>(jsonString, _serializerOptions); // JSON转对象
}
T?:C# 8+的可空类型(若T是引用类型,允许返回null);
JsonException:当JSON格式错误(如缺少括号、字段类型不匹配)时抛出,需单独捕获。
3. 测试程序
csharp
var testUsers = new List<User> { new User(1, "张三", ...), ... }; // 创建测试数据
UserPersistence.SerializeToFile(filePath, testUsers); // 保存到文件
var loadedUsers = UserPersistence.DeserializeFromFile<List<User>>(filePath); // 读取
foreach (var user in loadedUsers) Console.WriteLine(...) // 验证结果
测试流程:创建数据→序列化→反序列化→对比结果,确保数据一致性;
若手动修改users.json的内容(如删除某个括号),反序列化时会抛出JsonException,验证异常处理逻辑。
基础知识拓展
-
JSON核心概念
键值对:JSON基本单位(如"Name": "张三");
数组:用[]包裹多个对象(如[{"Id":1}, {"Id":2}]);
嵌套对象:对象内部包含其他对象(如"Address": {"City": "北京", "Street": "长安街"})。 - System.Text.Json核心组件
| 组件名 | 作用 |
|---|---|
| JsonSerializer | 静态类,提供Serialize(对象转JSON)和Deserialize(JSON转对象)方法 |
| JsonSerializerOptions | 配置序列化/反序列化规则(缩进、日期格式、忽略null等) |
| JsonPropertyNameAttribute | 自定义JSON字段名(如[JsonPropertyName("user_id")]将Id转为user_id) |
| JsonIgnoreAttribute | 忽略某个属性(如[JsonIgnore]标记Password字段不序列化) |
- System.Text.Json vs Newtonsoft.Json
| 特性 | System.Text.Json(微软官方) | Newtonsoft.Json(第三方) |
|---|---|---|
| 性能 | 更高(原生实现,无反射) | 略低(依赖反射) |
| 体积 | 更小(内置到.NET Core) | 需额外引用包 |
| 功能丰富度 | 基础功能齐全,高级功能少 | 功能强大(支持动态类型、LINQ) |
| 兼容性 | .NET Core 3.0+支持 | 支持所有.NET版本 |
选择建议:新项目优先用System.Text.Json(性能好、无依赖);若需复杂功能(如动态JSON处理),再考虑Newtonsoft.Json。
4. 持久化的其他方式
| 方式 | 优点 | 缺点 |
|---|---|---|
| JSON文件 | 轻量、易读、跨平台 | 不适合大量数据(查询慢) |
| XML文件 | 结构严谨、支持Schema验证 | 冗余度高、体积大 |
| SQLite数据库 | 支持结构化查询、事务、索引 | 需学习SQL语法 |
| 二进制序列化 | 体积小、速度快 | 不跨平台、可读性差 |
扩展思考
如何自定义JSON字段名?
给User类的属性加[JsonPropertyName]特性:
csharp
public class User
{
[JsonPropertyName("user_id")]
public int Id { get; set; }
}
序列化后Id会变为"user_id"。
如何忽略敏感属性?
给Password属性加[JsonIgnore]特性:
csharp
[JsonIgnore]
public string Password { get; set; } = string.Empty;
序列化时不会包含Password字段。
如何处理版本兼容?
若User类新增Age字段,旧JSON文件中无此字段,可通过JsonSerializerOptions设置默认值:
csharp
options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; // 忽略null值
options.MissingMemberHandling = JsonMissingMemberHandling.Ignore; // 忽略JSON中不存在的属性
如何异步序列化/反序列化? 使用异步文件操作方法:
csharp
public static async Task SerializeToFileAsync<T>(string filePath, T data)
{
string json = JsonSerializer.Serialize(data, _serializerOptions);
await File.WriteAllTextAsync(filePath, json, Encoding.UTF8);
}
总结
JSON序列化/反序列化是数据持久化的基础技术,通过System.Text.Json可快速实现对象与文件的转换。本实例的核心是掌握JsonSerializer的使用和JsonSerializerOptions的配置,同时需注意异常处理和数据安全(如敏感数据需加密后再序列化)。
在实际项目中,JSON不仅用于本地文件持久化,还广泛用于API接口数据交换(如前后端通信、微服务调用),是后端开发必备技能之一。
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49415.html










