Запись JSON в поток без буферизации строки в памяти

Я хотел бы написать JSON в Stream, явно создав документ. Например:

var stream = ...;
var writer = new JsonWriter(stream);

writer.BeginArray();
{
  writer.BeginObject();
  {
    writer.String("foo");
    writer.Number(1);
    writer.String("bar");
    writer.Number(2.3);
  }
  writer.EndObject();
}
writer.EndArray();

Это произведет:

[
  {
    "foo": 1,
    "bar": 2.3
  }
]

Преимущество этого подхода в том, что ничего не нужно буферизировать в памяти. В моей ситуации я пишу в поток довольно много JSON. Такие решения, как это, включают создание всех ваших объектов в памяти, затем их сериализацию в большую строку в памяти, а затем, наконец, запись эту строку в поток и сборку мусора, вероятно, из LOH. Я хочу, чтобы моя память использовалась на низком уровне, записывая элементы при чтении данных из другого потока файлов/БД/и т.д.

Такой подход доступен в C++ через rapidjson library.

Я искал немного для этого и не нашел решения.


person Drew Noakes    schedule 16.08.2013    source источник


Ответы (1)


Оказывается, мне нужно было Google немного дольше.

JSON.NET действительно поддерживает это через свой класс JsonWriter.

Мой пример будет написан:

Stream stream = ...;

using (var streamWriter = new StreamWriter(stream))
using (var writer = new JsonTextWriter(streamWriter))
{
    writer.Formatting = Formatting.Indented;

    writer.WriteStartArray();
    {
        writer.WriteStartObject();
        {
            writer.WritePropertyName("foo");
            writer.WriteValue(1);
            writer.WritePropertyName("bar");
            writer.WriteValue(2.3);
        }
        writer.WriteEndObject();
    }
    writer.WriteEndArray();
}
person Drew Noakes    schedule 16.08.2013
comment
Почему вы используете эти ненужные {, }? - person I4V; 16.08.2013
comment
И почему я должен явно писать все элементы вручную, а не просто делать jsonSerializer.Serialize(jsonTextWriter,obj) ? - person I4V; 16.08.2013
comment
@ I4V - {} предназначены для удобства чтения и не являются обязательными. В нетривиальном примере они действительно могут помочь. Написание элементов вручную — хорошая идея, если вам нужно написать много-много элементов, которые следуют простому повторяющемуся формату. Например, если вы записываете JSON в поток ответов HTTP, используя 100 000 элементов из SqlDataReader, запись таким образом позволяет избежать попадания OutOfMemoryException, и даже если у вас нет OOME, ваш веб-сервер будет работать намного лучше. Итак, это зависит от требований вашей ситуации. - person Drew Noakes; 16.08.2013
comment
@ I4V, кроме того, в моем случае я использую расположение типов шаблонов посетителей, где использование JsonWriter обеспечивает хорошую абстракцию, позволяя различным обработчикам писать все, что они хотят. - person Drew Noakes; 16.08.2013
comment
@ I4V Более того, это более эффективный подход. Сериализация всегда требует больших накладных расходов. Записывая вручную только те данные, которые необходимы, вы можете избежать большого объема работы. В конце концов, автоматическая сериализация требует проверки определенных атрибутов и анализа структуры объекта, что занимает значительно больше времени, чем его написание вручную. В своих проектах я пишу свои файлы вручную, потому что это может занять целую вечность с огромными объемами данных. И извините, я знаю, что эта тема устарела. Но я подумал, что это стоит упомянуть. - person SharpShade; 30.05.2017