当jsonTextReader.LinePosition超1000时NetworkStream反序列化JSON报错
问题场景回顾
你遇到的核心问题是:用Json.NET的JsonTextReader读取NetworkStream中的JSON对象时,一旦jsonTextReader.LinePosition超过1000就会抛出解析错误,但完全相同的JSON内容用MemoryStream读取却能正常工作。另外你受限于库代码,无法调整if (jsonTextReader.Read())在循环中的位置,也不能通过重建JsonTextReader来重置状态(这会导致无法处理单个长度超过1024的JSON对象)。
原因分析
首先要明确:LinePosition是JsonTextReader自身维护的解析状态属性,和NetworkStream/Socket没有直接的底层关联,问题的根源出在流式传输的分块特性和JsonTextReader的解析逻辑配合上:
NetworkStream是流式、非缓冲的网络传输流,数据可能分批次到达。而JsonTextReader依赖StreamReader的缓冲来读取字符,如果StreamReader的默认缓冲大小(通常是1024字节)不足以容纳当前正在解析的JSON片段,就会导致JsonTextReader在解析到LinePosition接近1000时,遇到不完整的字符序列,触发解析错误。MemoryStream是内存中的完整数据流,StreamReader可以一次性读取全部内容,自然不会出现分块解析导致的不完整问题。- 你提到重建
JsonTextReader能临时解决,本质是重置了解析状态(包括LinePosition),但这只是回避了问题——如果单个JSON对象长度超过1000,还是会再次触发错误。
针对性解决方案
结合你的代码限制,以下两种方案可以直接解决问题:
1. 给NetworkStream添加缓冲层
在NetworkStream外面套一层BufferedStream,确保StreamReader能获取到足够的缓冲数据,避免JsonTextReader解析时遇到不完整的字符:
// 初始化NetworkStream后,包装成BufferedStream,设置足够大的缓冲(比如4096字节) var bufferedStream = new BufferedStream(networkStream, 4096); var streamReader = new StreamReader(bufferedStream, new UTF8Encoding()); var jsonTextReader = new JsonTextReader(streamReader) { CloseInput = false, SupportMultipleContent = true };
这样可以让StreamReader一次性读取更多的网络数据,减少分块解析的概率,确保JsonTextReader能拿到完整的JSON片段进行解析。
2. 调整StreamReader的缓冲大小
直接初始化StreamReader时设置更大的缓冲大小,覆盖默认的1024字节限制:
// 第四个参数设置为更大的缓冲值,比如4096 var streamReader = new StreamReader(networkStream, new UTF8Encoding(), true, 4096); var jsonTextReader = new JsonTextReader(streamReader) { CloseInput = false, SupportMultipleContent = true };
这可以让StreamReader一次读取更多的网络数据,避免因为缓冲不足导致的JSON片段不完整问题。
报错细节解释
你提供的两个报错都是因为解析时遇到了不完整的JSON片段:
Unexpected character encountered while parsing number: T. Path 'timeStamp', line 1, position 1026:解析timestamp字段时,还没读完完整的日期字符串(如2018-05-14T07:52:23.3347793Z),就因为网络流没有后续数据,导致JsonTextReader错误地把T识别为数字的一部分。Invalid JavaScript property identifier character: ". Path 'message.indicator', line 1, position 1023:解析message.indicator字段时,还没读完字段名或对应的值,就遇到了不完整的字符,触发解析失败。
内容的提问来源于stack exchange,提问作者Xpleria

