首页 游戏 软件 资讯 排行榜 专题
首页
编程语言
c#如何读取JSON文件_c#读取JSON文件深入理解与底层原理

c#如何读取JSON文件_c#读取JSON文件深入理解与底层原理

热心网友
38
转载
2026-05-05

.NET 6+ JSON 文件读取最佳实践:System.Text.Json 反序列化、动态解析与流式处理详解

c#如何读取JSON文件_c#读取JSON文件深入理解与底层原理

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

使用 JsonSerializer.Deserialize 进行 JSON 反序列化:核心在于类型映射

当 JSON 数据结构稳定且字段定义清晰时,.NET 6 及以上版本内置的 System.Text.Json 库是处理 JSON 文件的首选方案。它无需引入任何外部依赖,序列化与反序列化路径高效,内存占用较低。然而,成功读取的关键并非功能本身,而在于类型定义的精确匹配——Deserialize 方法不会自动忽略 JSON 中多余的字段,也不会将字符串类型的 null 自动转换为数值类型的 0 或布尔类型的 false

开发者常遇到的错误提示是:JsonSerializer.Deserialize 抛出 JsonException: The JSON value could not be converted to xxx。这通常表明,C# 类中定义的属性类型与 JSON 文件中的实际值类型不兼容。例如,JSON 中某个值为带引号的字符串 "123",而 C# 属性却声明为 int 类型。

  • 确保目标类中所有非可空的引用类型属性,在 JSON 数据中均有对应的值。若字段可能缺失,应将其声明为可空类型,如 string?int?
  • 通过配置 JsonSerializerOptions.PropertyNameCaseInsensitive = true,可以有效解决因属性名大小写不一致导致的映射失败问题。
  • 若 JSON 中包含符合 ISO 8601 标准的日期字符串(例如 "2024-05-20T14:30:00"),可直接使用 DateTimeDateTimeOffset 类型属性接收,无需手动转换,这是库的默认支持行为。
  • 避免使用 objectdynamic 类型接收数据后再进行强制转换。这种做法绕过了编译时的类型安全检查,容易将问题隐藏至运行时,增加调试难度。

处理含注释或尾部逗号的非标准 JSON:启用宽松解析配置

.NET 原生的 JsonSerializer 默认遵循严格的 JSON 标准(RFC 8259 规范)。这意味着,行内注释(// comment)、块注释(/* comment */)以及对象或数组末尾多余的逗号(例如 {"a":1,}),默认情况下均不被接受。直接使用默认设置读取此类“非标准”JSON 文件,会立即抛出 JsonException 异常。

解决方案是启用宽松解析模式。具体而言,需要设置 JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip 以跳过注释,并设置 JsonSerializerOptions.AllowTrailingCommas = true 以允许尾部逗号。

参考配置示例如下:

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    ReadCommentHandling = JsonCommentHandling.Skip,
    AllowTrailingCommas = true
};
var data = JsonSerializer.Deserialize(File.ReadAllText("config.json"), options);

需要注意两点:首先,上述配置选项仅影响反序列化(读取)过程,对序列化(写入)操作无效;其次,即使启用了宽松模式,它仍然不支持单引号字符串或属性名不加引号等语法,这些已超出 JSON 标准范畴,若遇到此类情况,可能需要考虑使用其他更灵活的解析库。

动态 JSON 解析场景:轻量且安全的 JsonDocument 方案

当 JSON 数据结构不确定或需要动态查询时——例如处理配置片段、API 返回的部分动态数据或用户上传的未知格式文件——为每个结构定义完整的 C# 类可能不切实际。此时,JsonDocument 提供了一个比 Newtonsoft.Json 的 JObject 更轻量、内存效率更高的只读解析方案。它不会构建完整的对象图,仅解析必要的部分,非常适合“查询即用”的场景。

一个常见的误区是使用 JsonElement.Clone() 来多次访问同一节点。实际上,JsonElement 是结构体(struct),复制成本极低。真正需要警惕的是,在频繁调用 GetProperty 查询嵌套属性时,未使用 TryGetProperty 进行安全判断,从而导致 InvalidOperationException: Cannot access child value on a value of type Undefined 异常。

  • 最佳实践是始终优先使用 TryGetProperty("fieldName", out var element) 来检查属性是否存在,而非直接调用可能抛出异常的 root.GetProperty("fieldName")
  • 读取数值时,应使用类型明确的 element.GetInt32()element.GetDouble() 等方法,而非使用 element.ToString() 获取原始 JSON 文本再进行转换——后者可能包含额外的引号或空白符。
  • 使用 JsonDocument.Parse 解析 JSON 后,务必调用 Dispose() 方法释放底层资源,或直接使用 using 语句包裹以确保及时释放缓冲区。

高效读取大型 JSON 文件:避免内存溢出(OOM)的流式处理技巧

若使用 File.ReadAllText("huge.json") 加载数百 MB 甚至更大的 JSON 文件,程序会一次性分配与文件大小相当的内存用于存储字符串,极易引发频繁的垃圾回收(GC)甚至直接导致 OutOfMemoryException 异常。性能瓶颈往往不在于 JSON 解析本身,而在于初始的内存加载阶段。

正确的解决方案是采用流式处理(Streaming):结合 FileStreamUtf8JsonReader,实现边读取边解析,将内存占用控制在数 KB 的恒定水平。

此方案尤其适用于处理 JSON Lines 格式的日志文件、传感器批量上报数据或按行存储的数据库导出快照(每行一个独立 JSON 对象)。

  • 对于按行读取的场景,使用 File.ReadLines("data.jsonl").Select(line => JsonDocument.Parse(line)) 远比将整个文件读入内存再进行分割更为安全高效。
  • 若遇到结构复杂的超大单体 JSON 文件(如某些 GeoJSON 数据),则需要手动使用 Utf8JsonReader 进行增量读取,跳过不需要的深层数组或对象,仅提取关键字段,从而大幅降低内存消耗。
  • 性能优化提示:尽量避免在循环中重复创建 JsonSerializerOptions 实例。该对象设计为线程安全且可复用,多次创建会增加不必要的开销。

从底层实现来看,Utf8JsonReader 直接操作 UTF-8 编码的字节流,避免了中间字符串的生成;而 JsonSerializer.Deserialize 正是在其基础上封装了类型映射逻辑。因此,当面临“是否使用 Newtonsoft.Json”的选择时,本质上是进行功能与性能的权衡:若项目需要支持注释、宽松语法或复杂的自定义转换器等高级特性,可引入第三方库;若仅需高效、标准地处理 JSON,原生 System.Text.Json 在性能和资源开销上通常是更优的选择。

来源:https://www.php.cn/faq/2311842.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

C#怎么使用ReadOnlySpan_C#只读内存切片性能优化教程【高级】
编程语言
C#怎么使用ReadOnlySpan_C#只读内存切片性能优化教程【高级】

C ReadOnlySpan 使用指南:高性能只读内存切片优化技巧【高级教程】 在 NET 高性能编程实践中,尤其是在字符串处理场景,一个公认的高效策略是:直接采用 ReadOnlySpan 来替代传统的 string 参数以及中间的 Substring 调用。这是目前实现零分配、低开销处理的最

热心网友
05.06
c#如何实现分页查询_c#分页查询最全用法总结
编程语言
c#如何实现分页查询_c#分页查询最全用法总结

SQL Server分页首选OFFSET-FETCH,需配合ORDER BY且参数化传值;EF Core用Skip Take自动翻译,避免内存分页;大数据量时应改用游标分页。 SQL Server 中用 OFFSET-FETCH 做分页最直接 说到在SQL Server里做分页,2012及以上版本提

热心网友
05.06
c#如何批量插入数据_c#批量插入数据完整教程与实战案例
编程语言
c#如何批量插入数据_c#批量插入数据完整教程与实战案例

C 万级数据批量插入:SqlBulkCopy 实战精要 在C 中进行大规模数据插入,性能是首要考量。当数据量达到万级甚至更高时,常规的逐条插入方法会迅速成为性能瓶颈。那么,有没有一种既高效又稳定的解决方案呢?答案是肯定的。 用 SqlBulkCopy 实现高速批量插入 开门见山地说,在C 生态中,

热心网友
05.06
c#如何使用TestContainers集成测试_c#TestContainers集成测试的最佳实践与常见坑点
编程语言
c#如何使用TestContainers集成测试_c#TestContainers集成测试的最佳实践与常见坑点

C 中使用TestContainers进行集成测试:最佳实践与常见坑点 想在 NET 里玩转 TestContainers?这事儿说简单也简单,说麻烦也麻烦。简单在于,它确实能让你用几行代码就拉起一个数据库或中间件进行测试;麻烦在于,从环境配置到代码编写,每一步都有几个“经典”的坑在等着你。今天,

热心网友
05.06
C#怎么操作WPF Canvas画布绘图 C#如何在WPF Canvas上用代码动态绘制图形和连线【控件】
编程语言
C#怎么操作WPF Canvas画布绘图 C#如何在WPF Canvas上用代码动态绘制图形和连线【控件】

C WPF Canvas画布绘图完全指南:代码动态绘制图形与连线详解 Canvas直接添加子元素导致错位或不显示的解决方案 许多C 开发者在初次使用WPF Canvas控件进行动态绘图时,常会遇到一个典型问题:为何通过代码添加的Rectangle矩形或Line线条无法正常显示,或者出现位置偏移?

热心网友
05.06

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

荣耀400pro关机要按几秒
电脑教程
荣耀400pro关机要按几秒

荣耀400 Pro正确关机全指南:从常规操作到故障应对详解 需要关闭您的荣耀400 Pro手机?日常操作其实非常简便。只需长按位于机身右侧的电源键约3秒钟,屏幕上便会浮现一个简洁的半透明菜单,其中明确列出了“关机”、“重启”以及“紧急呼叫”选项。直接点击“关机”,系统将启动一次10秒的安全倒计时,随

热心网友
05.06
红米K30Pro如何拆后盖胶怎么清理
电脑教程
红米K30Pro如何拆后盖胶怎么清理

红米K30 Pro后盖拆解教程:专业工具与细致手法的完美结合 红米K30 Pro的后盖采用了高强度背胶配合隐藏式螺丝的双重固定设计,想要实现无损拆解,绝非依靠蛮力可以完成。整个操作流程对加热温度、撬启手法以及清洁标准都有严格要求,任何环节的疏忽都可能导致部件损伤。具体而言,其后盖边缘使用了耐高温的工

热心网友
05.06
三星zflip电池百分比需要root吗
电脑教程
三星zflip电池百分比需要root吗

无需Root权限:三星Galaxy Z Flip系列电量数字显示设置全解析 很多三星折叠屏手机用户都想知道,如何在状态栏直接查看精确的电池百分比数字,是否必须获取Root权限才能实现?实际上完全不需要。三星自Galaxy Z Flip 5、Z Flip 4等主流机型开始,已在系统层面内置了这一实用功

热心网友
05.06
笔记本开机自检时能看到DDR3或DDR4吗
电脑教程
笔记本开机自检时能看到DDR3或DDR4吗

笔记本开机自检信息虽不直接标注“DDR3”或“DDR4”,但联想、戴尔、华硕等品牌BIOS画面常以“PC3-”或“PC4-”编码间接揭示内存代际。UEFI自检显示的内存频率(如2400MHz 3200MHz)结合JEDEC规范可辅助推断:PC3对应DDR3,PC4对应DDR4。更高精度的识别方案包括

热心网友
05.06
空调制冷但不太凉是压缩机问题吗?
电脑教程
空调制冷但不太凉是压缩机问题吗?

空调制冷不足怎么办?先别急着维修压缩机,这些问题更常见 夏天开空调却感觉不够凉爽?很多朋友的第一反应是压缩机坏了,其实压缩机故障的概率相对较低。根据维修行业的大数据统计,绝大多数制冷效果不佳的情况,源于几个容易被忽略的日常维护与环境因素。滤网积尘、制冷剂泄漏、外机散热不良才是真正的高发原因。盲目更换

热心网友
05.06