2017-06-27 1 views
5

Ist es möglich, mit Json.NET zu NDJSON (Newline Delimited JSON) zu serialisieren? Die Elasticsearch-API verwendet NDJSON für Massenoperationen und ich kann nichts finden, was darauf hindeutet, dass dieses Format von beliebigen .NET-Bibliotheken unterstützt wird.Serialize als NDJSON mit Json.NET

This answer bietet eine Anleitung für Deserialisieren NDJSON, und es wurde festgestellt, dass man jede Zeile unabhängig serialisiert werden konnte und mit Newline beitreten, aber ich würde nicht unbedingt nennen das unterstützt.

+0

Dieser Link verweist auf einen Domain-Grab. Es wurde erst vor ein paar Jahren erstellt, während Anbieter wie AWS und Azure seit mehreren Jahren newline-delimeted JSON verwenden –

Antwort

4

Die einfachste Antwort auf eine einzige TextWriter unter Verwendung eines separaten JsonTextWriter für jede Zeile zu schreiben wäre, CloseOutput = false für jede Einstellung:

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"); 
     } 
    } 
} 

Probe fiddle.

Da die einzelnen NDJSON-Leitungen wahrscheinlich kurz sind, aber die Anzahl der Leitungen möglicherweise groß ist, schlägt diese Antwort eine Streaming-Lösung vor, die die Zuweisung einer einzelnen Zeichenfolge größer als 85 KB verhindert. Wie in Newtonsoft Json.NET Performance Tips erläutert, landen solche großen Strings auf dem large object heap und können nachfolgend die Anwendungsleistung verschlechtern.

+0

Akzeptieren als Antwort aufgrund der Verwendung eines JsonTextWriter. Es scheint, als ob dies der vernünftigste Ansatz im Kontext dessen ist, was die Bibliothek bereits bietet, und es ist merklich performanter als der Ansatz der anderen Antwort, einen neuen TextWriter für jede Zeile zu erzeugen. –

+0

Eigentlich ist das obige die Antwort, die einen JsonTextWriter für jede Zeile erstellt. – jlavallet

+1

@jlavallet - 'JsonConvert.SerializeObject()' erstellt intern sowohl einen 'StringWriter' als auch einen' JsonTextWriter'; Weitere Informationen finden Sie [hier] (https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/JsonConvert.cs#L647).Da die einzelnen JSON-Zeilen wahrscheinlich kurz sind, aber die Anzahl der Zeilen möglicherweise groß ist, schlug ich eine Streaming-Lösung vor, um zu vermeiden, dass eine einzelne Zeichenfolge größer als 85 kB zugewiesen wird (http://www.newtonsoft.com/json) /help/html/Performance.htm#MemoryUsage). – dbc

1

Sie konnten dieses versuchen:

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

aber jetzt sehe ich, dass Sie nicht nur das serialisierte Objekt wollen ziemlich gedruckt werden. Wenn das Objekt, das Sie serialisieren, irgendeine Sammlung oder Aufzählung ist, können Sie das nicht einfach selbst tun, indem Sie jedes Element serialisieren?

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

// use the NDJSON output 
Console.WriteLine(sb.ToString()); 
+0

Es wäre sicherlich gültig, eine Zeile zu einer Zeit zu serialisieren und anzuhängen, aber wie ich schon sagte: das ist keine Funktionalität Ich kann von Json.NET out-of-the-box erhalten. Es ist eine faire Frage, ob Json.NET _should_ dieses Format explizit unterstützen soll oder nicht. Was wäre der Eingabetyp für NDJson, ein Array von Objekten? –

+0

Ich stimme zu, dass es eine faire Frage ist, ob Json.NET dieses out-of-the-box unterstützen kann. – jlavallet

+0

Was der Eingabetyp wäre - ich nehme an, was ich schnell über das NDJSON-Format gelesen habe, hängt vom Kontext ab. Es wäre "eine Reihe von Daten", die getrennt von anderen "Datenzeilen" behandelt werden sollten. Was ist dein Kontext? Die Datenzeile könnte ein einfaches Objekt mit wenigen Eigenschaften, ein komplexes Objekt mit mehreren Ebenen von Unterobjekten oder nur eine Zeichenfolge sein. Sie müssten mir sagen, was in jeder Zeile erscheinen soll. – jlavallet

Verwandte Themen