如何在C#中用StreamReader读取JSON文件并跳过无效节点
解决方案:跳过大型JSON中的无效节点继续处理
问题场景
处理大型JSON数组时,部分节点存在格式错误(如示例中第一个对象"type": "message"后缺少逗号),需要跳过无效节点,继续处理后续有效内容,避免整个流程终止。
JSON示例:
[ { "id": "a5db927f-62b3-4b30-b520-83cff902c3ef", "type": "message" "parent": null, "participant": "mauraans", "body": "We've moved the meeting out. Apologies for the last minute changes. Appears daylight savings time has caused challenges with time zones.", "conversation": "D04QU11BTJN", "importance": "normal", "timestamp": "1680541760.235769", "lastmodifiedtime": null, "deleted": false }, { "id": "6db0169c-d8d9-4d27-8fa9-b60b9f163b87", "type": "message", "parent": null, "participant": "mauraans", "body": "What time did you have on your calendar and we'll go with that?", "conversation": "D04QU11BTJN", "importance": "normal", "timestamp": "1680539518.455199", "lastmodifiedtime": null, "deleted": false } ]
原代码问题
原代码在捕获JsonReaderException后直接调用reader.Skip(),但此时reader处于异常状态,无法正确识别当前节点的边界,Skip()无法准确定位到下一个有效节点,导致后续处理仍出错。
原代码:
using(FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { using(BufferedStream bufferedStream = new BufferedStream(fs, 5000)) { using(StreamReader r = new StreamReader(bufferedStream)) using(JsonTextReader reader = new JsonTextReader(r)) { JsonSerializer serializer = new JsonSerializer(); while (reader.Read()) { try { if (reader.TokenType == JsonToken.StartObject) { var node = serializer.Deserialize < dynamic > (reader); Console.WriteLine(node.id); nodeCount++; } } catch (JsonReaderException ex) { reader.Skip(); } } } } }
修正后的代码
核心思路:捕获异常后,手动遍历token并跟踪对象嵌套层级,确保完整跳过整个无效对象,直到找到下一个有效节点或数组结尾。
int nodeCount = 0; string filePath = "your-json-file-path.json"; using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (BufferedStream bufferedStream = new BufferedStream(fs, 5000)) using (StreamReader r = new StreamReader(bufferedStream)) using (JsonTextReader reader = new JsonTextReader(r)) { JsonSerializer serializer = new JsonSerializer(); while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { try { var node = serializer.Deserialize<dynamic>(reader); Console.WriteLine(node.id); nodeCount++; } catch (JsonReaderException) { // 手动跳过当前无效对象,处理嵌套层级 int depth = 1; while (depth > 0 && reader.Read()) { if (reader.TokenType == JsonToken.StartObject) depth++; else if (reader.TokenType == JsonToken.EndObject) depth--; } Console.WriteLine("跳过一个无效节点"); } } } } Console.WriteLine($"共处理有效节点数:{nodeCount}");
关键说明
- 异常捕获后通过
depth变量跟踪对象嵌套层级,确保完整跳过整个无效对象,不会停留在中间位置。 - 遍历token直到
depth归0(找到当前对象的EndObject)或到达数组结尾,保证后续reader能正确定位到下一个有效节点。 - 保持流式读取特性,适合处理大型JSON文件,不会将整个文件加载到内存中。
内容的提问来源于stack exchange,提问作者Savan Gangani
相关产品推荐
相关产品推荐

