2016-06-14 2 views
-3

알 수없는 JSON 문자열을 구문 분석하여 특정 키/값 쌍을 찾기 위해 작은 재귀 C# 응용 프로그램을 만들었습니다. Newtonsoft.Json.dll을 사용했습니다. 작은 JSON 문자열에서도 정상적으로 작동하지만 JSON이 더 큰 경우 시간이 오래 걸립니다. 3.5KB의 JSON 파일과 15K + 회선은 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 객체의 키/값 쌍

는 말했다되고 있다는 몇 가지 권장 할 수 있습니다 Performance Tips: Optimize Memory Usage에 설명 된대로

  1. 오히려 큰 (3.5 MB) 문자열로 JSON을로드하는 대신, 당신은 파일에서 직접 스트리밍합니다.

  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 디스크에 파일을 열어 만들었습니다.