代码之家  ›  专栏  ›  技术社区  ›  Optional Option

使用Newtonsoft.JSON[duplicate]读取多个JSON对象(连接的JSON)

  •  0
  • Optional Option  · 技术社区  · 6 年前

    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对象的方法?

    1 回复  |  直到 6 年前
        1
  •  3
  •   Optional Option    6 年前

    此解决方案基于Newtonsoft.JSON版本12.0.1。它可能在将来起作用,也可能不起作用。

    首先,我们需要一个更好的 JsonTextReader

        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。