C#中的增量JSON解析

时间:2012-01-26 22:37:14

标签: c# json parsing

我试图逐步解析JSON,即基于条件。

下面是我的json消息,我目前正在使用JavaScriptSerializer来反序列化消息。

string json = @"{"id":2,
"method":"add",
"params":
   {"object":
       {"name":"test"
        "id":"1"},
        "position":"1"}
  }";

JavaScriptSerializer js = new JavaScriptSerializer();
Message m = js.Deserialize<Message>(json);

消息类如下所示:

 public class Message
 {
        public string id { get; set; }
        public string method { get; set; }
        public Params @params { get; set; }
        public string position { get; set; }
 }
public class Params
{
        public string name { get; set; }
        public string id{ get; set; 
}

上面的代码解析消息没有问题。但它会立即解析整个JSON。我希望它仅在“method”参数的值为“add”时才进行解析。如果它不是“添加”,那么我不希望它继续解析其余的消息。有没有办法根据C#中的条件进行增量解析? (环境:VS 2008与.Net 3.5)

6 个答案:

答案 0 :(得分:14)

我必须承认我对JavaScriptSerializer并不熟悉,但如果您愿意使用JSON.net,则其JsonReader的行为与DataReader非常相似。

using(var jsonReader = new JsonTextReader(myTextReader)){
  while(jsonReader.Read()){
    //evaluate the current node and whether it's the name you want
    if(jsonReader.TokenType.PropertyName=="add"){
      //do what you want
    } else {
      //break out of loop.
    }
  }
}

答案 1 :(得分:9)

以下是我用来解析,加载和创建非常大的JSON文件的通用和简单方法。该代码现在使用了非常标准的JSON.Net库。不幸的是,关于如何做到这一点的文档并不是很清楚,但要弄清楚它也不是很难。

下面的代码假设您希望序列化为JSON数组的大量对象,反之亦然。我们希望支持非常大的文件,这些文件的大小仅受存储设备(不是内存)的限制。因此,在序列化时,该方法需要IEnumerable<T>,而反序列化则返回相同的值。这样您就可以处理整个文件而不受内存的限制。

used this code文件大小为几GB且性能合理。

//Serialize sequence of objects as JSON array in to a specified file
public static void SerializeSequenceToJson<T>(this IEnumerable<T> sequence, string fileName)
{
    using (var fileStream = File.CreateText(fileName))
        SerializeSequenceToJson(sequence, fileStream);
}

//Deserialize specified file in to IEnumerable assuming it has array of JSON objects
public static IEnumerable<T> DeserializeSequenceFromJson<T>(string fileName)
{
    using (var fileStream = File.OpenText(fileName))
        foreach (var responseJson in DeserializeSequenceFromJson<T>(fileStream))
            yield return responseJson;
}

//Utility methods to operate on streams instead of file
public static void SerializeSequenceToJson<T>(this IEnumerable<T> sequence, TextWriter writeStream, Action<T, long> progress = null)
{
    using (var writer = new JsonTextWriter(writeStream))
    {
        var serializer = new JsonSerializer();
        writer.WriteStartArray();
        long index = 0;
        foreach (var item in sequence)
        {
            if (progress != null)
                progress(item, index++);

            serializer.Serialize(writer, item);
        }
        writer.WriteEnd();
    }
}
public static IEnumerable<T> DeserializeSequenceFromJson<T>(TextReader readerStream)
{
    using (var reader = new JsonTextReader(readerStream))
    {
        var serializer = new JsonSerializer();
        if (!reader.Read() || reader.TokenType != JsonToken.StartArray)
            throw new Exception("Expected start of array in the deserialized json string");

        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.EndArray) break;
            var item = serializer.Deserialize<T>(reader);
            yield return item;
        }
    }
}

答案 2 :(得分:5)

如果您查看Json.NET,它会提供一个非缓存,仅向前的JSON解析器,以满足您的需求。

请参阅documentation中的JsonReaderJsonTextReader课程。

答案 3 :(得分:2)

我目前处于未知时间跨度的第3小时,看着160GB的JSON被反序列化为类对象。我的内存使用一直在大约350MB,当我检查内存对象时,GC可以照顾所有内容。这是我做的:

    FileStream fs = File.Open("F:\\Data\\mysuperbig150GB.json", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    StreamReader sr = new StreamReader(fs);

    using (JsonReader reader = new JsonTextReader(sr))
    {
        JsonSerializer serializer = new JsonSerializer();

        MyJsonToClass result = serializer.Deserialize<MyJsonToClass>(reader);
    }

问题在于反序列化。 160GB的数据比我的PC可以同时处理的数据大得多。

  1. 我使用了一个小片段(很难,甚至只是打开一个160GB的文件)并通过jsontochsarp获得了一个类结构。

  2. 我在auto-generated-via-json-tool类结构中为big集合创建了一个特定的类,并且子类化了System.Collection.ObjectModel.ObservableCollection而不是List。它们都实现了IEnumberable,我认为这是Newtsonsoft JSON解串器所关心的。

  3. 我进去并覆盖了InsertItem,就像这样:

    protected override void InsertItem(int index, Feature item)
    {
      //do something with the item that just got deserialized
      //stick it in a database, etc.
      RemoveItem(0);
    }
    
  4. 同样,我的问题部分是关于JSON反序列化速度,但超出了我无法将~160GB的JSON数据放入集合中。即使收紧,它也会出现在数十个演出区域,比.net更令人满意。

    ObservableCollection上的InsertItem是我所知道的唯一可以在反序列化时处理的方法。 List.Add()没有。我知道这个解决方案并不“优雅”,但是当我键入它时它正在工作。

答案 4 :(得分:1)

你想要一个用于JSON的SAX类型解析器

http://en.wikipedia.org/wiki/Simple_API_for_XML

http://www.saxproject.org/event.html

SAX在解析文档的每一部分时引发一个事件。

考虑到JSON语法的简单性,在JSON中做类似的事情(应该)非常简单。

这个问题可能有所帮助:Is there a streaming API for JSON?

另一个链接:https://www.p6r.com/articles/2008/05/22/a-sax-like-parser-for-json/

答案 5 :(得分:0)

这种方法的原因是什么?如果您担心的是性能,则可能是“过早优化”,或者换句话说,担心可能不存在的问题。

我强烈建议你不要担心这个细节。构建您的应用程序,如果速度不够快,请使用分析工具找到实际的瓶颈 - 它们可能不会出现在您预期的位置。

在了解问题之前关注性能几乎总会导致时间浪费和代码过多。