【问题标题】:Serialize as NDJSON using Json.NET使用 Json.NET 序列化为 NDJSON
【发布时间】:2017-06-27 18:43:50
【问题描述】:

是否可以使用 Json.NET 序列化为 NDJSON(换行符分隔的 JSON)? Elasticsearch API 使用 NDJSON 进行批量操作,我找不到任何表明 任何 .NET 库支持这种格式的信息。

This answer 提供了反序列化 NDJSON 的指导,并指出可以独立序列化每一行并使用换行符加入,但我不一定称其为支持

【问题讨论】:

  • 该链接指向域抓取。它仅在几年前创建,而 AWS 和 Azure 等提供商使用换行符分隔的 JSON 已有好几年了

标签: c# json json.net ndjson


【解决方案1】:

由于 Json.NET 目前没有将集合序列化为 NDJSON 的内置方法,因此最简单的答案是使用单独的 JsonTextWriter 为每一行写入单个 TextWriter,设置 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);
            }
            // https://web.archive.org/web/20180513150745/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");
        }
    }
}

示例fiddle

由于单个 NDJSON 行可能很短但行数可能很大,因此此答案建议采用流式解决方案来避免分配大于 85kb 的单个字符串的必要性。正如Newtonsoft Json.NET Performance Tips 中所解释的,如此大的字符串最终会出现在large object heap 上,并可能随后降低应用程序性能。

【讨论】:

  • 由于使用了 JsonTextWriter 而接受作为答案。在库已经提供的内容的上下文中,这似乎是最理智的方法,并且它明显比其他答案为每行创建一个新的 TextWriter 的方法性能更高。
  • 其实上面的答案就是为每一行创建一个JsonTextWriter。
  • @jlavallet - JsonConvert.SerializeObject() 在内部同时创建 StringWriterJsonTextWriter;有关详细信息,请参阅here。由于单个 JSON 行可能很短,但行数可能很大,因此我建议使用流式解决方案来避免分配大于 85kb 的单个字符串,推荐 here
【解决方案2】:

你可以试试这个:

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());

【讨论】:

  • 一次序列化一行并追加当然是有效的,但正如我所指出的:这不是我可以从开箱即用的 Json.NET 获得的功能。 Json.NET 应该 是否明确支持这种格式是一个公平的问题。 NDJson 的输入类型是什么,一个对象数组?
  • 我同意 Json.NET 是否可以开箱即用地支持这个问题是一个公平的问题。
  • 至于输入类型是什么——我想根据我快速阅读的有关 NDJSON 格式的内容,这将取决于上下文。这将是“一行数据”,应该与其他“数据行”分开处理。你的背景是什么?数据行可以是具有几个属性的简单对象,也可以是具有多级子对象的复杂对象,或者只是一个字符串,您必须告诉我每行应该显示什么。
  • @jlvallet NDJSON 允许以这种格式传输 any 有效的 JSON。如果您想在 .NET 中使用一组混合对象生成此输出,则需要某种类型的装箱/拆箱。无论如何,这更多的是作为修辞提示。也许最好的实现是简单地为这种类型的序列化构建一个自定义 JsonTextWriter,避免库中的任何直接支持。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多