使用Newtonsoft.JSON读取多个JSON对象(串联的JSON)

时间:2018-12-28 19:05:01

标签: c# json.net

C#Newtonsoft.JSON库在大多数情况下都能很好地工作,但是没有一种简单的方法来读取concatenated 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对象?

1 个答案:

答案 0 :(得分:2)

此解决方案基于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。