Сериализация как NDJSON с использованием Json.NET

Можно ли сериализовать в NDJSON ( Newline Delimited JSON), используя Json.NET? Elasticsearch API использует NDJSON для массовых операций, и я не могу найти ничего, свидетельствующего о том, что этот формат поддерживается любыми библиотеками.NET.

Этот ответ дает руководство по десериализации NDJSON, и было отмечено, что можно сериализовать каждую строку независимо и присоединиться к новой строке, но я не обязательно буду называть это поддерживаемым.

2 ответа

Решение

Простейшим ответом будет написать один TextWriter используя отдельный JsonTextWriter для каждой строки настройка CloseOutput = false для каждого:

public static partial class JsonExtensions
{
    public static void ToNewlineDelimitedJson<T>(Stream stream, IEnumerable<T> items)
    {
        // Let caller dispose the underlying stream 
        using (var textWriter = new StreamWriter(stream, new UTF8Encoding(false, true), 1024, true))
        {
            ToNewlineDelimitedJson(textWriter, items);
        }
    }

    public static void ToNewlineDelimitedJson<T>(TextWriter textWriter, IEnumerable<T> items)
    {
        var serializer = JsonSerializer.CreateDefault();

        foreach (var item in items)
        {
            // Formatting.None is the default; I set it here for clarity.
            using (var writer = new JsonTextWriter(textWriter) { Formatting = Formatting.None, CloseOutput = false })
            {
                serializer.Serialize(writer, item);
            }
            // http://specs.okfnlabs.org/ndjson/
            // Each JSON text MUST conform to the [RFC7159] standard and MUST be written to the stream followed by the newline character \n (0x0A). 
            // The newline charater MAY be preceeded by a carriage return \r (0x0D). The JSON texts MUST NOT contain newlines or carriage returns.
            textWriter.Write("\n");
        }
    }
}

Образец скрипки.

Поскольку отдельные строки NDJSON, вероятно, будут короткими, но число строк может быть большим, этот ответ предлагает потоковое решение, чтобы избежать необходимости выделять одну строку размером более 85 КБ. Как объясняется в Совете по повышению производительности Json.NET от Newtonsoft, такие большие строки попадают в кучу больших объектов и могут впоследствии снизить производительность приложения.

Вы можете попробовать это:

string ndJson = JsonConvert.SerializeObject(value, Formatting.Indented);

но теперь я вижу, что вы хотите не просто печатать сериализованный объект. Если объект, который вы сериализуете, является неким набором или перечислением, не могли бы вы сделать это самостоятельно, сериализовав каждый элемент?

StringBuilder sb = new StringBuilder();
foreach (var element in collection)
{
    sb.AppendLine(JsonConvert.SerializeObject(element, Formatting.None));
}

// use the NDJSON output
Console.WriteLine(sb.ToString());
Другие вопросы по тегам