2016-06-14 10 views
-3

私は小さな再帰C#アプリケーションを作成して、未知のJSON文字列を解析し、Newtonsoft.Json.dllを使って特定のキー/値のペアを見つけました。小さなJSON文字列ではうまくいきますが、JSONが大きければ時間がかかります:3.5KバイトのJSONファイルでは解析に3分以上かかります。 RegExpを使用して同じファイルを解析すると、1秒で<となります。それはJsonConvert.DeserializeObject()にかかるのですか?JSON DeserializeObjectが非常に遅い

string json = @"{""origin-of_error"" : ""error_message"",""foo"" : ""bar""}"; 
    static void GetJsonValue (string json, string findStr = "foo") 
    { 
     try 
     { 

      if (Regex.Match(json, @"^\[", RegexOptions.Multiline).Success) 
      { 
       // JSON string Array [] 
       var jArr = JsonConvert.DeserializeObject<List<Object>>(json); 
       foreach (var jLine in jArr) GetJsonValue(jLine.ToString()); 
      } 
      else 
      { 
       // JSON string KEY:VALUE 
       var jLog = JsonConvert.DeserializeObject<Dictionary<String, Object>>(json);    
       foreach (KeyValuePair<string, object> jEntry in jLog) 
       { 
        if (jEntry.Key.ToString() == findStr) Console.WriteLine("MATCH:" + jEntry.ToString()); 
        GetJsonValue(jEntry.Value.ToString()); 
       }      
      } 
     } 
     catch { } 
    } 
+2

Regexのマッチをオブジェクトの作成と比較することはできませんが、それはもっと複雑です。あなたは疑問を持っていますか?これはちょうど変装の暴言ですか? – Liam

+1

JSONをここで何度も何度も解析していることに注意してください。 'JObject'にそれを解析して再帰的に調べてみてはどうでしょうか? –

+0

これは簡単な方法でした。そのような時間がかかるとは予想していませんでした。 – kestasj

答えて

1

それはあなたの問題は、あなたの実際のJSONのサンプルを含んでいないので、何であるか本当に明確ではありません、しかし、あなたが順番に大きなJSON配列の値をデシリアライズしようとしている表示されます、またはの値ディスク上のファイルに格納されている場合、大きなJSONオブジェクトのキー/値ペア。言われて、いくつかの提言を行うことができること

  1. むしろより大きな(3.5 MB)文字列にJSONを読み込むには、Performance Tips: Optimize Memory Usageに説明するように、ファイルから直接ストリーミングする必要があります。

  2. あなたの現在のアプローチは、大規模な一時Dictionary<string, object>またはList<object>にデシリアライズし、各値のために、文字列に再シリアライズし、これをデシリアライズするためのようです。これは演奏されません。

    デシリアライズしようとしている値が複雑なオブジェクトの場合は、解決策をParsing large json file in .NETから変更して、ルートJSONコンテナが配列またはオブジェクトである可能性があるという事実を処理できます。

    したがって、代わりに、使用:(あなたの例に示されるように、すなわち文字列だけで、)

    public static partial class JsonExtensions 
    { 
        public static IEnumerable<T> DeserializeValues<T>(Stream stream) 
        { 
         return DeserializeValues<T>(new StreamReader(stream)); 
        } 
    
        public static IEnumerable<T> DeserializeValues<T>(TextReader textReader) 
        { 
         var serializer = JsonSerializer.CreateDefault(); 
         var reader = new JsonTextReader(textReader); 
         reader.SupportMultipleContent = true; 
         while (reader.Read()) 
         { 
          if (reader.TokenType == JsonToken.StartArray) 
          { 
           while (reader.Read()) 
           { 
            if (reader.TokenType == JsonToken.Comment) 
             continue; // Do nothing 
            else if (reader.TokenType == JsonToken.EndArray) 
             break; // Break from the loop 
            else 
             yield return serializer.Deserialize<T>(reader); 
           } 
          } 
          else if (reader.TokenType == JsonToken.StartObject) 
          { 
           while (reader.Read()) 
           { 
            if (reader.TokenType == JsonToken.Comment) 
             continue; // Do nothing 
            else if (reader.TokenType == JsonToken.PropertyName) 
             continue; // Eat the property name 
            else if (reader.TokenType == JsonToken.EndObject) 
             break; // Break from the loop 
            else 
             yield return serializer.Deserialize<T>(reader); 
           } 
          } 
         } 
        } 
    } 
    
  3. あなたがデシリアライズしようとしている値がプリミティブている場合は、完全にデシリアライズ飛ばしてください、直接読んでください。デシリアライズには通常、リフレクションによってdata contractの作成と処理が必要です。読書はこの複雑さを直接スキップします。

    このようにあなたができる:#2、#3の両方について

    public static partial class JsonExtensions 
    { 
        public static bool IsPrimitive(this JsonToken tokenType) 
        { 
         switch (tokenType) 
         { 
          case JsonToken.Integer: 
          case JsonToken.Float: 
          case JsonToken.String: 
          case JsonToken.Boolean: 
          case JsonToken.Undefined: 
          case JsonToken.Null: 
          case JsonToken.Date: 
          case JsonToken.Bytes: 
           return true; 
          default: 
           return false; 
         } 
        } 
    
        public static IEnumerable<string> ReadPrimitives(Stream stream) 
        { 
         return ReadPrimitives(new StreamReader(stream)); 
        } 
    
        public static IEnumerable<string> ReadPrimitives(TextReader textReader) 
        { 
         var reader = new JsonTextReader(textReader); 
         reader.SupportMultipleContent = true; 
         while (reader.Read()) 
         { 
          if (reader.TokenType.IsPrimitive()) 
          { 
           if (reader.TokenType == JsonToken.String) 
            yield return reader.Value.ToString(); // No need for conversion 
           else 
            yield return (string)JValue.Load(reader); // Convert to string. 
          } 
         } 
        } 
    } 
    

を、あなたはディスク上のファイルを開くことにより、作成したStreamまたはStreamReaderを渡します。