c#如何读取JSON文件_c#读取JSON文件深入理解与底层原理
.NET 6+ JSON 文件读取最佳实践:System.Text.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"),可直接使用DateTime或DateTimeOffset类型属性接收,无需手动转换,这是库的默认支持行为。 - 避免使用
object或dynamic类型接收数据后再进行强制转换。这种做法绕过了编译时的类型安全检查,容易将问题隐藏至运行时,增加调试难度。
处理含注释或尾部逗号的非标准 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):结合 FileStream 与 Utf8JsonReader,实现边读取边解析,将内存占用控制在数 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 在性能和资源开销上通常是更优的选择。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
Laravel如何在事务中处理文件上传与数据库联动_Laravel文件与DB事务协调方法【存储】
Lara vel中文件上传与数据库操作的原子性保障:五种实战策略 在Lara vel应用开发中,一个经典的挑战是:当文件上传与数据库记录写入必须作为一个不可分割的整体时,如何确保两者要么同时成功,要么同时失败?毕竟,文件系统操作并不天然支持数据库那样的事务回滚。别担心,下面这五种经过实战检验的方法,
PHP怎么实现Flux CD自动化同步_PHP GitOps工具链集成【方法】
PHP项目如何通过Flux CD实现GitOps自动化部署:完整集成指南 Flux CD 能否直接在PHP应用中运行? 答案是否定的。Flux CD本质上是一个专为Kubernetes设计的GitOps控制器,采用Go语言开发,并以独立Pod的形式运行于集群的flux-system命名空间内。这意味
C++实现基于时间戳的限流算法 _ 令牌桶与漏桶原理实现【源码】
C++实现基于时间戳的限流算法:令牌桶与漏桶原理实现【源码】 开门见山,先说结论:在C++服务端开发中,利用std::chrono配合原子变量,完全可以构建出线程安全且开销极低的令牌桶限流器。至于漏桶算法,在纯内存的服务端限流场景里,其实很少有必要去实现——它的核心是“恒定速率输出”,而服务端限流真
如何在 XAMPP 中配置 PHP 的 max_execution_time 执行超时时间
如何在 XAMPP 中配置 PHP 的 max_execution_time 执行超时时间 直接修改 php ini 并重启 Apache 服务,是唯一可靠且永久生效的方法;其他临时方案在 XAMPP 集成环境中要么效果有限,要么不推荐用于生产部署。 如何定位并修改 XAMPP 的 php ini
golang如何编译WebAssembly_golang编译WebAssembly实践
编译WebAssembly必须设GOOS=js且GOARCH=wasm;需配套wasm_exec js胶水代码;Go与JS交互须用syscall js Value;fmt Println默认不输出;异步操作需JS回调;init()中避免阻塞。 编译前必须确认 GOOS 和 GOARCH 设置正确 想
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

