C# Newtonsoft.JSON 库在大多数情况下运行良好,但没有简单的方法来读取串联的 JSON,如下所示:
{"some":"thing"}{"some":"other thing"}{"some":"third thing"}
这段代码非常简单,但如果我尝试反序列化多个对象,它会引发异常:
using (var reader = new StreamReader(File.Open("data.txt", FileMode.Open)))
{
using (var jr = new JsonTextReader(reader))
{
var data1 = js.Deserialize<Data>(jr));
var data2 = js.Deserialize<Data>(jr)); // <--- Exception is thrown here
}
}
有几种解决方法。第一个是将整个对象列表重新格式化为 JSON 数组。这种方法适用于少量数据,但如果文件不适合内存,那么情况就会变得非常复杂。
另一种解决方法是将整个文本拆分为单独的 JSON 对象,并一次分析一个对象。此解决方案将处理大量数据,但实现有点复杂,因为它需要某种 JSON 解析。
有没有更简单的方法可以在这种级联的 JSON 文件中读取 JSON 对象?
此解决方案基于 Newtonsoft.JSON 版本 12.0.1。将来可能会也可能不会起作用。
首先,我们需要一个更好的 JsonTextReader,它将在反序列化 JSON 对象后重置为可用状态。
public class MyJsonTextReader : JsonTextReader
{
public MyJsonTextReader(TextReader textReader) : base(textReader)
{
SupportMultipleContent = true;
}
public bool ObjectDone()
{
base.SetStateBasedOnCurrent();
try
{
// This call works fine at the end of the file but may throw JsonReaderException
// if some bad character follows our JSON object
return !base.Read();
}
catch (JsonReaderException)
{
return true;
}
}
}
使用新的 JSON 读取器类反序列化代码可以像这样稍作修改:
var all = new List<Data>();
var js = new JsonSerializer();
using (var reader = new StreamReader(File.Open("data.txt", FileMode.Open)))
using (var jr = new MyJsonTextReader(reader))
do
{
all.Add(js.Deserialize<Data>(jr));
} while (!jr.ObjectDone());
此解决方案可以读取无限数量的对象。ObjectDone() 函数在文件末尾或在反序列化对象后面出现无效字符的情况下返回 false。