Použití třídy DOM, Utf8JsonReader a Utf8JsonWriter v nástroji System.Text.Json

Důležité

Některé informace se týkají předběžné verze produktu, který může být podstatně změněn před jeho vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Tento článek popisuje, jak používat:

Poznámka

Další informace o těchto rozhraních API najdete v článku o migraci z Odysoftu. Projděte si následující části tohoto článku:

Volby modelu DOM JSON

Práce s modelu DOM je alternativou k deserializaci:

  • Pokud nemáte typ, do který chcete deserializovat.
  • Pokud kód JSON, který obdržíte, nemá pevné schéma a je třeba ho zkontrolovat, abyste věděli, co obsahuje.

System.Text.Json nabízí dva způsoby, jak vytvořit JSON DOM:

  • JsonDocument poskytuje možnost sestavit pomocí modelu DOM jen pro Utf8JsonReader čtení. K elementům JSON, které tvoří datovou část, je možné získat přístup přes JsonElement typ . Typ poskytuje enumerátory polí a objektů spolu s rozhraními API pro JsonElement převod textu JSON na běžné typy .NET. JsonDocument zpřístupňuje RootElement vlastnost. Další informace najdete v části Použití objektu JsonDocument dále v tomto článku.

Při výběru mezi a zvažte následující JsonDocument JsonNode faktory:

  • Po JsonNode vytvoření modelu DOM je možné ho změnit. Dom JsonDocument je neměnný.
  • Dom JsonDocument poskytuje rychlejší přístup ke svým datům.
  • Počínaje rozhraním .NET 6 a třídy, které jsou z něj odvozeny v oboru názvů, poskytují možnost vytvořit JsonNode System.Text.Json.Nodes mutable DOM. Další informace najdete v tomto článku ve verzi .NET 6.

Použití JsonNode

Následující příklad ukazuje, jak použít a další typy v oboru názvů JsonNode System.Text.Json.Nodes pro:

  • Vytvoření modelu DOM z řetězce JSON
  • Zápis JSON z modelu DOM
  • Získá hodnotu, objekt nebo pole z modelu DOM.
using System;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace JsonNodeFromStringExample
{
    public class Program
    {
        public static void Main()
        {
            string jsonString =
@"{
  ""Date"": ""2019-08-01T00:00:00"",
  ""Temperature"": 25,
  ""Summary"": ""Hot"",
  ""DatesAvailable"": [
    ""2019-08-01T00:00:00"",
    ""2019-08-02T00:00:00""
  ],
  ""TemperatureRanges"": {
      ""Cold"": {
          ""High"": 20,
          ""Low"": -10
      },
      ""Hot"": {
          ""High"": 60,
          ""Low"": 20
      }
  }
}
";
            // Create a JsonNode DOM from a JSON string.
            JsonNode forecastNode = JsonNode.Parse(jsonString);

            // Write JSON from a JsonNode
            var options = new JsonSerializerOptions { WriteIndented = true };
            Console.WriteLine(forecastNode.ToJsonString(options));
            // output:
            //{
            //  "Date": "2019-08-01T00:00:00",
            //  "Temperature": 25,
            //  "Summary": "Hot",
            //  "DatesAvailable": [
            //    "2019-08-01T00:00:00",
            //    "2019-08-02T00:00:00"
            //  ],
            //  "TemperatureRanges": {
            //    "Cold": {
            //      "High": 20,
            //      "Low": -10
            //    },
            //    "Hot": {
            //      "High": 60,
            //      "Low": 20
            //    }
            //  }
            //}

            // Get value from a JsonNode.
            JsonNode temperatureNode = forecastNode["Temperature"];
            Console.WriteLine($"Type={temperatureNode.GetType()}");
            Console.WriteLine($"JSON={temperatureNode.ToJsonString()}");
            //output:
            //Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
            //JSON = 25

            // Get a typed value from a JsonNode.
            int temperatureInt = (int)forecastNode["Temperature"];
            Console.WriteLine($"Value={temperatureInt}");
            //output:
            //Value=25

            // Get a typed value from a JsonNode by using GetValue<T>.
            temperatureInt = forecastNode["Temperature"].GetValue<int>();
            Console.WriteLine($"TemperatureInt={temperatureInt}");
            //output:
            //Value=25

            // Get a JSON object from a JsonNode.
            JsonNode temperatureRanges = forecastNode["TemperatureRanges"];
            Console.WriteLine($"Type={temperatureRanges.GetType()}");
            Console.WriteLine($"JSON={temperatureRanges.ToJsonString()}");
            //output:
            //Type = System.Text.Json.Nodes.JsonObject
            //JSON = { "Cold":{ "High":20,"Low":-10},"Hot":{ "High":60,"Low":20} }

            // Get a JSON array from a JsonNode.
            JsonNode datesAvailable = forecastNode["DatesAvailable"];
            Console.WriteLine($"Type={datesAvailable.GetType()}");
            Console.WriteLine($"JSON={datesAvailable.ToJsonString()}");
            //output:
            //datesAvailable Type = System.Text.Json.Nodes.JsonArray
            //datesAvailable JSON =["2019-08-01T00:00:00", "2019-08-02T00:00:00"]

            // Get an array element value from a JsonArray.
            JsonNode firstDateAvailable = datesAvailable[0];
            Console.WriteLine($"Type={firstDateAvailable.GetType()}");
            Console.WriteLine($"JSON={firstDateAvailable.ToJsonString()}");
            //output:
            //Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
            //JSON = "2019-08-01T00:00:00"

            // Get a typed value by chaining references.
            int coldHighTemperature = (int)forecastNode["TemperatureRanges"]["Cold"]["High"];
            Console.WriteLine($"TemperatureRanges.Cold.High={coldHighTemperature}");
            //output:
            //TemperatureRanges.Cold.High = 20

            // Parse a JSON array
            var datesNode = JsonNode.Parse(@"[""2019-08-01T00:00:00"",""2019-08-02T00:00:00""]");
            JsonNode firstDate = datesNode[0].GetValue<DateTime>();
            Console.WriteLine($"firstDate={ firstDate}");
            //output:
            //firstDate = "2019-08-01T00:00:00"
        }
    }
}

Vytvoření modelu DOM JsonNode s inicializátory objektů a provedení změn

Následující příklad ukazuje, jak:

  • Vytvořte model DOM pomocí inicializátorů objektů.
  • Proveďte změny modelu DOM.
using System;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace JsonNodeFromObjectExample
{
    public class Program
    {
        public static void Main()
        {
            // Create a new JsonObject using object initializers.
            var forecastObject = new JsonObject
            {
                ["Date"] = new DateTime(2019, 8, 1),
                ["Temperature"] = 25,
                ["Summary"] = "Hot",
                ["DatesAvailable"] = new JsonArray(
                    new DateTime(2019, 8, 1), new DateTime(2019, 8, 2)),
                ["TemperatureRanges"] = new JsonObject
                {
                    ["Cold"] = new JsonObject
                    {
                        ["High"] = 20,
                        ["Low"] = -10
                    }
                },
                ["SummaryWords"] = new JsonArray("Cool", "Windy", "Humid")
            };

            // Add an object.
            forecastObject["TemperatureRanges"].AsObject().Add(
                "Hot", new JsonObject { ["High"] = 60, ["Low"] = 20 });

            // Remove a property.
            forecastObject.Remove("SummaryWords");

            // Change the value of a property.
            forecastObject["Date"] = new DateTime(2019, 8, 3);

            var options = new JsonSerializerOptions { WriteIndented = true };
            Console.WriteLine(forecastObject.ToJsonString(options));
            //output:
            //{
            //  "Date": "2019-08-03T00:00:00",
            //  "Temperature": 25,
            //  "Summary": "Hot",
            //  "DatesAvailable": [
            //    "2019-08-01T00:00:00",
            //    "2019-08-02T00:00:00"
            //  ],
            //  "TemperatureRanges": {
            //    "Cold": {
            //      "High": 20,
            //      "Low": -10
            //    },
            //    "Hot": {
            //      "High": 60,
            //      "Low": 20
            //    }
            //  }
            //}
        }
    }
}

Deserializace pododdílů datové části JSON

Následující příklad ukazuje, jak pomocí uzlu JsonNode přejít k pododdílu stromu JSON a deserializovat jednu hodnotu, vlastní typ nebo pole z tohoto pododdílu.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace JsonNodePOCOExample
{
    public class TemperatureRanges : Dictionary<string, HighLowTemps>
    {
    }

    public class HighLowTemps
    {
        public int High { get; set; }
        public int Low { get; set; }
    }

    public class Program
    {
        public static DateTime[] DatesAvailable { get; set; }

        public static void Main()
        {
            string jsonString =
 @"{
  ""Date"": ""2019-08-01T00:00:00"",
  ""Temperature"": 25,
  ""Summary"": ""Hot"",
  ""DatesAvailable"": [
    ""2019-08-01T00:00:00"",
    ""2019-08-02T00:00:00""
  ],
  ""TemperatureRanges"": {
      ""Cold"": {
          ""High"": 20,
          ""Low"": -10
      },
      ""Hot"": {
          ""High"": 60,
          ""Low"": 20
      }
  }
}
";
            // Parse all of the JSON.
            JsonNode forecastNode = JsonNode.Parse(jsonString);

            // Get a single value
            int hotHigh = forecastNode["TemperatureRanges"]["Hot"]["High"].GetValue<int>();
            Console.WriteLine($"Hot.High={hotHigh}");
            // output:
            //Hot.High=60

            // Get a subsection and deserialize it into a custom type.
            JsonObject temperatureRangesObject = forecastNode["TemperatureRanges"].AsObject();
            using var stream = new MemoryStream();
            using var writer = new Utf8JsonWriter(stream);
            temperatureRangesObject.WriteTo(writer);
            writer.Flush();
            TemperatureRanges temperatureRanges = 
                JsonSerializer.Deserialize<TemperatureRanges>(stream.ToArray());
            Console.WriteLine($"Cold.Low={temperatureRanges["Cold"].Low}, Hot.High={temperatureRanges["Hot"].High}");
            // output:
            //Cold.Low=-10, Hot.High=60

            // Get a subsection and deserialize it into an array.
            JsonArray datesAvailable = forecastNode["DatesAvailable"].AsArray();
            Console.WriteLine($"DatesAvailable[0]={datesAvailable[0]}");
            // output:
            //DatesAvailable[0]=8/1/2019 12:00:00 AM
        }
    }
}

Následující příklad vybere pole JSON, které obsahuje celočíselné hodnoty a vypočítá průměrnou hodnotu:

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace JsonNodeAverageGradeExample
{
    public class Program
    {
        public static DateTime[] DatesAvailable { get; set; }

        public static void Main()
        {
            string jsonString =
 @"{
  ""Class Name"": ""Science"",
  ""Teacher\u0027s Name"": ""Jane"",
  ""Semester"": ""2019-01-01"",
  ""Students"": [
    {
      ""Name"": ""John"",
      ""Grade"": 94.3
    },
    {
      ""Name"": ""James"",
      ""Grade"": 81.0
    },
    {
      ""Name"": ""Julia"",
      ""Grade"": 91.9
    },
    {
      ""Name"": ""Jessica"",
      ""Grade"": 72.4
    },
    {
      ""Name"": ""Johnathan""
    }
  ],
  ""Final"": true
}
";
            double sum = 0;
            int count = 0;

            JsonNode document = JsonNode.Parse(jsonString);

            JsonNode root = document.Root;
            JsonArray studentsArray = root["Students"].AsArray();

            count = studentsArray.Count;

            foreach (JsonNode student in studentsArray)
            {
                if (student["Grade"] is JsonNode gradeNode)
                {
                    sum += (double)gradeNode;
                }
                else
                {
                    sum += 70;
                }
            }

            double average = sum / count;
            Console.WriteLine($"Average grade : {average}");
        }
    }
}
// output:
//Average grade : 81.92

Předchozí kód:

  • Vypočítá průměrnou třídu pro objekty v Students poli, které mají Grade vlastnost .
  • Přiřadí studentům, kteří nemají známku, výchozí známky 70.
  • Získá počet studentů z Count vlastnosti JsonArray .

Použití JsonDocument

Následující příklad ukazuje, jak použít třídu JsonDocument pro náhodný přístup k datům v řetězci JSON:

double sum = 0;
int count = 0;

using (JsonDocument document = JsonDocument.Parse(jsonString))
{
    JsonElement root = document.RootElement;
    JsonElement studentsElement = root.GetProperty("Students");
    foreach (JsonElement student in studentsElement.EnumerateArray())
    {
        if (student.TryGetProperty("Grade", out JsonElement gradeElement))
        {
            sum += gradeElement.GetDouble();
        }
        else
        {
            sum += 70;
        }
        count++;
    }
}

double average = sum / count;
Console.WriteLine($"Average grade : {average}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
    Dim root As JsonElement = document.RootElement
    Dim studentsElement As JsonElement = root.GetProperty("Students")
    For Each student As JsonElement In studentsElement.EnumerateArray()
        Dim gradeElement As JsonElement = Nothing
        If student.TryGetProperty("Grade", gradeElement) Then
            sum += gradeElement.GetDouble()
        Else
            sum += 70
        End If
        count += 1
    Next
End Using

Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")

Předchozí kód:

  • Předpokládá, že JSON k analýze je v řetězci s názvem jsonString .
  • Vypočítá průměrnou třídu pro objekty v Students poli, které mají Grade vlastnost .
  • Přiřadí studentům, kteří nemají známku, výchozí známky 70.
  • Vytvoří JsonDocument instanci v using příkazu , protože JsonDocument implementuje IDisposable . Jakmile JsonDocument je instance odstraněna, ztratíte také přístup ke všem JsonElement jejím instancím. Pokud chcete zachovat přístup k instanci, vytvořte kopii před uvolněním JsonElement JsonDocument nadřazené instance. Pokud chcete vytvořit kopii, zavolejte JsonElement.Clone . Další informace najdete v tématu JsonDocument is IDisposable.

Předchozí příklad kódu spočítá studenty zvýšením proměnné count s každou iterací. Alternativou je volání GetArrayLength , jak je znázorněno v následujícím příkladu:

double sum = 0;
int count = 0;

using (JsonDocument document = JsonDocument.Parse(jsonString))
{
    JsonElement root = document.RootElement;
    JsonElement studentsElement = root.GetProperty("Students");

    count = studentsElement.GetArrayLength();

    foreach (JsonElement student in studentsElement.EnumerateArray())
    {
        if (student.TryGetProperty("Grade", out JsonElement gradeElement))
        {
            sum += gradeElement.GetDouble();
        }
        else
        {
            sum += 70;
        }
    }
}

double average = sum / count;
Console.WriteLine($"Average grade : {average}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
    Dim root As JsonElement = document.RootElement
    Dim studentsElement As JsonElement = root.GetProperty("Students")

    count = studentsElement.GetArrayLength()

    For Each student As JsonElement In studentsElement.EnumerateArray()
        Dim gradeElement As JsonElement = Nothing
        If student.TryGetProperty("Grade", gradeElement) Then
            sum += gradeElement.GetDouble()
        Else
            sum += 70
        End If
    Next
End Using

Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")

Tady je příklad kódu JSON, který tento kód zpracuje:

{
  "Class Name": "Science",
  "Teacher\u0027s Name": "Jane",
  "Semester": "2019-01-01",
  "Students": [
    {
      "Name": "John",
      "Grade": 94.3
    },
    {
      "Name": "James",
      "Grade": 81.0
    },
    {
      "Name": "Julia",
      "Grade": 91.9
    },
    {
      "Name": "Jessica",
      "Grade": 72.4
    },
    {
      "Name": "Johnathan"
    }
  ],
  "Final": true
}

Použití JsonDocument k zápisu JSON

Následující příklad ukazuje, jak zapsat JSON z JsonDocument :

string jsonString = File.ReadAllText(inputFileName);

var writerOptions = new JsonWriterOptions
{
    Indented = true
};

var documentOptions = new JsonDocumentOptions
{
    CommentHandling = JsonCommentHandling.Skip
};

using FileStream fs = File.Create(outputFileName);
using var writer = new Utf8JsonWriter(fs, options: writerOptions);
using JsonDocument document = JsonDocument.Parse(jsonString, documentOptions);

JsonElement root = document.RootElement;

if (root.ValueKind == JsonValueKind.Object)
{
    writer.WriteStartObject();
}
else
{
    return;
}

foreach (JsonProperty property in root.EnumerateObject())
{
    property.WriteTo(writer);
}

writer.WriteEndObject();

writer.Flush();
Dim jsonString As String = File.ReadAllText(inputFileName)

Dim writerOptions As JsonWriterOptions = New JsonWriterOptions With {
    .Indented = True
}

Dim documentOptions As JsonDocumentOptions = New JsonDocumentOptions With {
    .CommentHandling = JsonCommentHandling.Skip
}

Dim fs As FileStream = File.Create(outputFileName)
Dim writer As Utf8JsonWriter = New Utf8JsonWriter(fs, options:=writerOptions)
Dim document As JsonDocument = JsonDocument.Parse(jsonString, documentOptions)

Dim root As JsonElement = document.RootElement

If root.ValueKind = JsonValueKind.[Object] Then
    writer.WriteStartObject()
Else
    Return
End If

For Each [property] As JsonProperty In root.EnumerateObject()
    [property].WriteTo(writer)
Next

writer.WriteEndObject()

writer.Flush()

Předchozí kód:

  • Přečte soubor JSON, načte data do souboru a zapíše formátovaný JsonDocument (poměrně tištěný) JSON do souboru.
  • Pomocí JsonDocumentOptions určuje, že komentáře ve vstupním formátu JSON jsou povolené, ale ignorují se.
  • Po dokončení volá Flush zapisovač. Alternativou je nechat zapisovač automaticky vyprázdnit, když je odstraněn.

Tady je příklad vstupu JSON, který se má zpracovat pomocí příkladu kódu:

{"Class Name": "Science","Teacher's Name": "Jane","Semester": "2019-01-01","Students": [{"Name": "John","Grade": 94.3},{"Name": "James","Grade": 81.0},{"Name": "Julia","Grade": 91.9},{"Name": "Jessica","Grade": 72.4},{"Name": "Johnathan"}],"Final": true}

Výsledkem je následující poměrně vytištěný výstup JSON:

{
  "Class Name": "Science",
  "Teacher\u0027s Name": "Jane",
  "Semester": "2019-01-01",
  "Students": [
    {
      "Name": "John",
      "Grade": 94.3
    },
    {
      "Name": "James",
      "Grade": 81.0
    },
    {
      "Name": "Julia",
      "Grade": 91.9
    },
    {
      "Name": "Jessica",
      "Grade": 72.4
    },
    {
      "Name": "Johnathan"
    }
  ],
  "Final": true
}

Použití Utf8JsonWriter

Utf8JsonReader je vysoce výkonná čtečka s nízkou alokací, která se používá pouze pro dopředné čtení textu JSON s kódováním UTF-8 a čte z ReadOnlySpan<byte> nebo ReadOnlySequence<byte> . je typ nízké úrovně, který lze použít k sestavení vlastních Utf8JsonReader analyzátorů a deserializátorů. Metoda JsonSerializer.Deserialize používá Utf8JsonReader pod pokryvem. Utf8JsonReaderNelze použít přímo z Visual Basic kódu. Další informace najdete v tématu Visual Basic podporu.

Následující příklad ukazuje, jak použít Utf8JsonWriter třídu :

var options = new JsonWriterOptions
{
    Indented = true
};

using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream, options);

writer.WriteStartObject();
writer.WriteString("date", DateTimeOffset.UtcNow);
writer.WriteNumber("temp", 42);
writer.WriteEndObject();
writer.Flush();

string json = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(json);
Dim options As JsonWriterOptions = New JsonWriterOptions With {
    .Indented = True
}

Dim stream As MemoryStream = New MemoryStream
Dim writer As Utf8JsonWriter = New Utf8JsonWriter(stream, options)

writer.WriteStartObject()
writer.WriteString("date", DateTimeOffset.UtcNow)
writer.WriteNumber("temp", 42)
writer.WriteEndObject()
writer.Flush()

Dim json As String = Encoding.UTF8.GetString(stream.ToArray())
Console.WriteLine(json)

Zápis nezpracovaných souborů JSON

V některých scénářích můžete chtít zapsat "nezpracovaný" JSON do datové části JSON, kterou vytváříte pomocí Utf8JsonWriter . Tady jsou typické scénáře:

  • Máte existující datovou část JSON, kterou chcete uzavřít do nového formátu JSON.

  • Hodnoty chcete formátovat odlišně od výchozího formátování Utf8JsonWriter.

    Můžete například chtít přizpůsobit formátování čísel. Ve výchozím nastavení vynechán desetinnou čárku System.Text.Json pro celá čísla, 1 zápis místo 1.0 , například. Důvodem je, že zápis menšího počtu bajtů je dobrý pro výkon. Předpokládejme ale, že příjemce vašeho FORMÁTU JSON považuje čísla s desetinnými místy za dvojité a čísla bez desetinných míst jako celá čísla. Můžete chtít zajistit, aby byla všechna čísla v poli rozpoznána jako dvojité, a to zápisem desetinné čárky a nuly pro celá čísla. Následující příklad ukazuje, jak to provést:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.Json;
    using System.Threading.Tasks;
    
    namespace WriteRawJson
    {
        public class Program
        {
            public static void Main()
            {
                JsonWriterOptions writerOptions = new() { Indented = true, };
    
                using MemoryStream stream = new();
                using Utf8JsonWriter writer = new(stream, writerOptions);
    
                writer.WriteStartObject();
    
                writer.WriteStartArray("defaultJsonFormatting");
                foreach (double number in new double[] { 50.4, 51 })
                {
                    writer.WriteStartObject();
                    writer.WritePropertyName("value");
                    writer.WriteNumberValue(number);
                    writer.WriteEndObject();
                }
                writer.WriteEndArray();
    
                writer.WriteStartArray("customJsonFormatting");
                foreach (double result in new double[] { 50.4, 51 })
                {
                    writer.WriteStartObject();
                    writer.WritePropertyName("value");
                    writer.WriteRawValue(
                        FormatNumberValue(result), skipInputValidation: true);
                    writer.WriteEndObject();
                }
                writer.WriteEndArray();
    
                writer.WriteEndObject();
                writer.Flush();
    
                string json = Encoding.UTF8.GetString(stream.ToArray());
                Console.WriteLine(json);
            }
            static string FormatNumberValue(double numberValue)
            {
                return numberValue == Convert.ToInt32(numberValue) ? 
                    numberValue.ToString() + ".0" : numberValue.ToString();
            }
        }
    }
    // output:
    //{
    //  "defaultJsonFormatting": [
    //    {
    //      "value": 50.4
    //    },
    //    {
    //      "value": 51
    //    }
    //  ],
    //  "customJsonFormatting": [
    //    {
    //      "value": 50.4
    //    },
    //    {
    //      "value": 51.0
    //    }
    //  ]
    //}
    

Použití Utf8JsonReader

Následující příklad ukazuje, jak použít Utf8JsonReader třídu :

var options = new JsonReaderOptions
{
    AllowTrailingCommas = true,
    CommentHandling = JsonCommentHandling.Skip
};
var reader = new Utf8JsonReader(jsonUtf8Bytes, options);

while (reader.Read())
{
    Console.Write(reader.TokenType);

    switch (reader.TokenType)
    {
        case JsonTokenType.PropertyName:
        case JsonTokenType.String:
            {
                string text = reader.GetString();
                Console.Write(" ");
                Console.Write(text);
                break;
            }

        case JsonTokenType.Number:
            {
                int intValue = reader.GetInt32();
                Console.Write(" ");
                Console.Write(intValue);
                break;
            }

            // Other token types elided for brevity
    }
    Console.WriteLine();
}
' This code example doesn't apply to Visual Basic. For more information, go to the following URL:
' https://docs.microsoft.com/dotnet/standard/serialization/system-text-json-how-to#visual-basic-support

Předchozí kód předpokládá, že proměnná je bajtové pole, které obsahuje platný kód jsonUtf8 JSON kódovaný jako UTF-8.

Filtrování dat pomocí Utf8JsonReader

Následující příklad ukazuje, jak synchronně načíst soubor a vyhledat hodnotu.

using System;
using System.IO;
using System.Text;
using System.Text.Json;

namespace SystemTextJsonSamples
{
    public class Utf8ReaderFromFile
    {
        private static readonly byte[] s_nameUtf8 = Encoding.UTF8.GetBytes("name");
        private static ReadOnlySpan<byte> Utf8Bom => new byte[] { 0xEF, 0xBB, 0xBF };

        public static void Run()
        {
            // ReadAllBytes if the file encoding is UTF-8:
            string fileName = "UniversitiesUtf8.json";
            ReadOnlySpan<byte> jsonReadOnlySpan = File.ReadAllBytes(fileName);

            // Read past the UTF-8 BOM bytes if a BOM exists.
            if (jsonReadOnlySpan.StartsWith(Utf8Bom))
            {
                jsonReadOnlySpan = jsonReadOnlySpan.Slice(Utf8Bom.Length);
            }

            // Or read as UTF-16 and transcode to UTF-8 to convert to a ReadOnlySpan<byte>
            //string fileName = "Universities.json";
            //string jsonString = File.ReadAllText(fileName);
            //ReadOnlySpan<byte> jsonReadOnlySpan = Encoding.UTF8.GetBytes(jsonString);

            int count = 0;
            int total = 0;

            var reader = new Utf8JsonReader(jsonReadOnlySpan);

            while (reader.Read())
            {
                JsonTokenType tokenType = reader.TokenType;

                switch (tokenType)
                {
                    case JsonTokenType.StartObject:
                        total++;
                        break;
                    case JsonTokenType.PropertyName:
                        if (reader.ValueTextEquals(s_nameUtf8))
                        {
                            // Assume valid JSON, known schema
                            reader.Read();
                            if (reader.GetString().EndsWith("University"))
                            {
                                count++;
                            }
                        }
                        break;
                }
            }
            Console.WriteLine($"{count} out of {total} have names that end with 'University'");
        }
    }
}
' This code example doesn't apply to Visual Basic. For more information, go to the following URL:
' https://docs.microsoft.com/dotnet/standard/serialization/system-text-json-how-to#visual-basic-support

Asynchronní verzi tohoto příkladu najdete v tématu Ukázky .NET v projektu JSON.

Předchozí kód:

  • Předpokládá, že JSON obsahuje pole objektů a každý objekt může obsahovat vlastnost "name" typu string.

  • Spočítá hodnoty objektů a vlastností "name", které končí na University.

  • Předpokládá, že je soubor kódovaný jako UTF-16 a překóduje ho do UTF-8. Soubor kódovaný jako UTF-8 lze číst přímo do a ReadOnlySpan<byte> pomocí následujícího kódu:

    ReadOnlySpan<byte> jsonReadOnlySpan = File.ReadAllBytes(fileName);
    

    Pokud soubor obsahuje znak pořadí bajtů UTF-8 (BOM), odeberte ho před předáním bajtů do Utf8JsonReader , protože čtecí modul očekává text. V opačném případě se kusovník považuje za neplatný kód JSON a čtenář vyvolá výjimku.

Zde je ukázka JSON, kterou může předchozí kód přečíst. Výsledná Souhrnná zpráva je "2 z čtvrtého" má názvy, které končí na "University" ":

[
  {
    "web_pages": [ "https://contoso.edu/" ],
    "alpha_two_code": "US",
    "state-province": null,
    "country": "United States",
    "domains": [ "contoso.edu" ],
    "name": "Contoso Community College"
  },
  {
    "web_pages": [ "http://fabrikam.edu/" ],
    "alpha_two_code": "US",
    "state-province": null,
    "country": "United States",
    "domains": [ "fabrikam.edu" ],
    "name": "Fabrikam Community College"
  },
  {
    "web_pages": [ "http://www.contosouniversity.edu/" ],
    "alpha_two_code": "US",
    "state-province": null,
    "country": "United States",
    "domains": [ "contosouniversity.edu" ],
    "name": "Contoso University"
  },
  {
    "web_pages": [ "http://www.fabrikamuniversity.edu/" ],
    "alpha_two_code": "US",
    "state-province": null,
    "country": "United States",
    "domains": [ "fabrikamuniversity.edu" ],
    "name": "Fabrikam University"
  }
]

Čtení z datového proudu pomocí Utf8JsonReader

Při čtení velkého souboru (například GB nebo více) můžete chtít, abyste nemuseli celý soubor načítat do paměti najednou. V tomto scénáři můžete použít FileStream .

Při použití nástroje Utf8JsonReader ke čtení z datového proudu platí následující pravidla:

  • Vyrovnávací paměť obsahující částečnou datovou část JSON musí být alespoň stejně velká jako největší token JSON, aby čtenář mohl provést postup.
  • Vyrovnávací paměť musí být alespoň tak velká jako největší sekvence prázdných znaků ve formátu JSON.
  • Čtenář neuchovává data, která si přečte, dokud úplně nepřečte další TokenType část v datové části JSON. Takže pokud jsou v bufferu zbývající bajty, je nutné je znovu předat čtečce. Můžete použít BytesConsumed k určení, kolik bajtů zbývá.

Následující kód ilustruje, jak číst z datového proudu. Příklad ukazuje MemoryStream . Podobný kód bude pracovat s FileStream , s výjimkou případů, kdy FileStream obsahuje kusovník UTF-8 na začátku. V takovém případě je nutné tyto tři bajty z vyrovnávací paměti oddělit před předáním zbývajících bajtů Utf8JsonReader . V opačném případě čtecí modul vyvolal výjimku, protože kusovník není považován za platnou součást formátu JSON.

Vzorový kód začíná vyrovnávací pamětí 4KB a zdvojnásobuje velikost vyrovnávací paměti pokaždé, když zjistí, že velikost není dostatečně velká, aby odpovídala kompletnímu tokenu JSON, který je vyžadován pro čtenáře, aby mohl v datové části JSON přesměrovat průběh. Ukázka JSON, která je obsažená ve fragmentu, vyvolá zvýšení velikosti vyrovnávací paměti pouze v případě, že nastavíte velmi malou počáteční velikost vyrovnávací paměti, například 10 bajtů. Pokud nastavíte počáteční velikost vyrovnávací paměti na hodnotu 10, Console.WriteLine příkazy ilustrují příčinu a účinek zvýšení velikosti vyrovnávací paměti. Na počáteční velikosti vyrovnávací paměti 4KB se každý ukázkový JSON zobrazí celý vzor JSON Console.WriteLine a velikost vyrovnávací paměti není nikdy potřeba zvýšit.

using System;
using System.IO;
using System.Text;
using System.Text.Json;

namespace SystemTextJsonSamples
{
    public class Utf8ReaderPartialRead
    {
        public static void Run()
        {
            var jsonString = @"{
                ""Date"": ""2019-08-01T00:00:00-07:00"",
                ""Temperature"": 25,
                ""TemperatureRanges"": {
                    ""Cold"": { ""High"": 20, ""Low"": -10 },
                    ""Hot"": { ""High"": 60, ""Low"": 20 }
                },
                ""Summary"": ""Hot"",
            }";

            byte[] bytes = Encoding.UTF8.GetBytes(jsonString);
            var stream = new MemoryStream(bytes);

            var buffer = new byte[4096];

            // Fill the buffer.
            // For this snippet, we're assuming the stream is open and has data.
            // If it might be closed or empty, check if the return value is 0.
            stream.Read(buffer);

            // We set isFinalBlock to false since we expect more data in a subsequent read from the stream.
            var reader = new Utf8JsonReader(buffer, isFinalBlock: false, state: default);
            Console.WriteLine($"String in buffer is: {Encoding.UTF8.GetString(buffer)}");

            // Search for "Summary" property name
            while (reader.TokenType != JsonTokenType.PropertyName || !reader.ValueTextEquals("Summary"))
            {
                if (!reader.Read())
                {
                    // Not enough of the JSON is in the buffer to complete a read.
                    GetMoreBytesFromStream(stream, ref buffer, ref reader);
                }
            }

            // Found the "Summary" property name.
            Console.WriteLine($"String in buffer is: {Encoding.UTF8.GetString(buffer)}");
            while (!reader.Read())
            {
                // Not enough of the JSON is in the buffer to complete a read.
                GetMoreBytesFromStream(stream, ref buffer, ref reader);
            }
            // Display value of Summary property, that is, "Hot".
            Console.WriteLine($"Got property value: {reader.GetString()}");
        }

        private static void GetMoreBytesFromStream(
            MemoryStream stream, ref byte[] buffer, ref Utf8JsonReader reader)
        {
            int bytesRead;
            if (reader.BytesConsumed < buffer.Length)
            {
                ReadOnlySpan<byte> leftover = buffer.AsSpan((int)reader.BytesConsumed);

                if (leftover.Length == buffer.Length)
                {
                    Array.Resize(ref buffer, buffer.Length * 2);
                    Console.WriteLine($"Increased buffer size to {buffer.Length}");
                }

                leftover.CopyTo(buffer);
                bytesRead = stream.Read(buffer.AsSpan(leftover.Length));
            }
            else
            {
                bytesRead = stream.Read(buffer);
            }
            Console.WriteLine($"String in buffer is: {Encoding.UTF8.GetString(buffer)}");
            reader = new Utf8JsonReader(buffer, isFinalBlock: bytesRead == 0, reader.CurrentState);
        }
    }
}
' This code example doesn't apply to Visual Basic. For more information, go to the following URL:
' https://docs.microsoft.com/dotnet/standard/serialization/system-text-json-how-to#visual-basic-support

Předchozí příklad nastavuje bez omezení na to, jak velké množství vyrovnávací paměti může růst. Pokud je velikost tokenu příliš velká, může dojít k selhání kódu s OutOfMemoryException výjimkou. K tomu může dojít, pokud JSON obsahuje token, který má velikost přibližně 1 GB nebo větší velikost, protože zdvojnásobení velikosti 1 GB má za následek velikost, která je příliš velká, aby se vešla do int32 vyrovnávací paměti.

:::zone-end

Viz také