Инкрементный анализ JSON в С#
Я пытаюсь разобрать 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". Если это не "добавить", я не хочу, чтобы он продолжал разбирать остальную часть сообщения. Есть ли способ сделать инкрементный синтаксический анализ на основе условия в С#? (Окружающая среда: VS 2008 с .Net 3.5)
Ответы
Ответ 1
Я должен признать, что я не так хорошо знаком с JavaScriptSerializer, но если вы открыты для использования JSON.net, он имеет JsonReader
, который действует как a DataReader
.
using(var jsonReader = new JsonTextReader(myTextReader)){
while(jsonReader.Read()){
//evaluate the current node and whether it the name you want
if(jsonReader.TokenType.PropertyName=="add"){
//do what you want
} else {
//break out of loop.
}
}
}
Ответ 2
Вот общие и простые методы, которые я использую для синтаксического анализа, загрузки и создания очень больших файлов JSON. В этом коде используется стандартная библиотека JSON.Net. К сожалению, документация не очень понятна, как это сделать, но и не очень сложно это понять.
Ниже код предполагает сценарий, в котором у вас есть большое количество объектов, которые вы хотите сериализовать как массив JSON, и наоборот. Мы хотим поддерживать очень большие размеры файлов, размер которых ограничен только вашим устройством хранения (а не памятью). Поэтому при сериализации метод принимает IEnumerable<T>
, и при десериализации он возвращает то же самое. Таким образом, вы можете обрабатывать весь файл, не ограничиваясь памятью.
Я использовал этот код для размера файлов в несколько ГБ с разумной производительностью.
//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;
}
}
}
Ответ 3
Если вы посмотрите Json.NET, он предоставляет не кеширование, только JSON для прямого доступа парсер, который удовлетворит ваши потребности.
См. класс JsonReader
и JsonTextReader
в документации .
Ответ 4
Сейчас я нахожусь в часе 3 неизвестного времени, наблюдая, как 160 ГБ JSON десериализуются в объекты класса. Мое использование памяти сильно зависало при ~ 350 МБ, и когда я проверяю объекты памяти, все это может занять 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);
}
Проблема заключается в десериализации. Это 160 ГБ данных намного больше, чем мой компьютер может обрабатывать сразу.
-
Я использовал небольшой фрагмент (который является жестким, даже просто открывающим файл размером 160 ГБ) и получил структуру класса через jsontochsarp.
-
Я создал специальный класс для большой коллекции в структуре класса с автоматическим генерированием-через-json-инструмент и подклассифицировал System.Collection.ObjectModel.ObservableCollection вместо списка. Они оба реализуют IEnumberable, который, как мне кажется, относится к десериализатору Newtsonsoft JSON.
-
Я включил и перевернул 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);
}
Опять же, мои проблемы, когда частично о скорости десериализации JSON, но кроме того, я не мог вместить ~ 160 ГБ данных JSON в коллекцию. Даже затянулось, это было бы в десятках концертных площадок, намного больше, чем .net будет счастлив.
InsertItem on ObservableCollection - единственный метод, который я знаю о том, что вы можете обрабатывать, когда происходит десериализация. List.Add() нет. Я знаю, что это решение не "элегантно", но оно работает, когда я печатаю это.
Ответ 5
Вам понадобится парсер SAX-типа для JSON
http://en.wikipedia.org/wiki/Simple_API_for_XML
http://www.saxproject.org/event.html
SAX вызывает событие, когда он анализирует каждую часть документа.
Выполнение чего-то подобного в JSON было бы (должно) довольно простым, учитывая, насколько прост синтаксис JSON.
Этот вопрос может помочь: Есть ли потоковый API для JSON?
И еще одна ссылка: https://www.p6r.com/articles/2008/05/22/a-sax-like-parser-for-json/
Ответ 6
В чем причина такого подхода? Если речь идет о производительности, то это, скорее всего, "преждевременная оптимизация", или, другими словами, беспокоиться о проблеме, которая может не существовать.
Я настоятельно призываю вас не беспокоиться об этой детали. Создайте приложение, а затем, если оно недостаточно быстро, используйте инструменты профилирования для определения фактических узких мест - скорее всего, они не будут там, где вы ожидаете.
Сосредоточившись на производительности, прежде чем зная ее, проблема почти всегда приводит к потере времени и чрезмерному коду.