İçinde JSON belgesi, Utf8JsonReader ve Utf8JsonWriter kullanma System.Text.Json

Bu makalede, ' nin nasıl kullanılacağı gösterilmektedir:

JSON DOM seçimleri

DOM ile çalışma, ile seri durumdan çıkarma için bir alternatiftir JsonSerializer :

  • Seri durumdan çıkarılacak bir tür yoksa.
  • Aldığınız JSON sabit bir şemaya sahip olmadığında ve neleri içerip içermediğinden emin olmak için incelenmelidir.

System.Text.Json JSON DOM oluşturmak için iki yol sunar:

  • JsonDocument kullanarak salt okunurdur bir DOM oluşturma yeteneği sağlar Utf8JsonReader . Yükü oluşturan JSON öğelerine tür aracılığıyla erişilebilir JsonElement . JsonElementTürü, JSON metnini ortak .net türlerine dönüştürmek Için API 'lerle birlikte dizi ve nesne numaralandırıcıları sağlar. JsonDocument bir RootElement özellik sunar. Daha fazla bilgi için bu makalenin ilerleyen kısımlarında yer alarak JsonDocument kullanma bölümüne bakın.

Ve arasında seçim yaparken aşağıdaki faktörleri göz önünde bulundurun JsonDocument JsonNode :

  • JsonNodeDom oluşturulduktan sonra değiştirilebilir. JsonDocumentDom sabittir.
  • JsonDocumentDom, verilerine daha hızlı erişim sağlar.

JsonNode komutunu kullanma

Aşağıdaki örnek, JsonNode ad alanındaki diğer türlerin ve için nasıl kullanılacağını gösterir System.Text.Json.Nodes :

  • JSON dizesinden DOM oluşturma
  • DOM 'dan JSON yazın.
  • DOM 'dan bir değer, nesne veya dizi alın.
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"
        }
    }
}

Nesne başlatıcıları ile bir JsonNode DOM oluşturma ve değişiklik yapma

Aşağıdaki örnek, aşağıdakilerin nasıl yapılacağını göstermektedir:

  • Nesne başlatıcıları kullanarak bir DOM oluşturun.
  • DOM üzerinde değişiklikler yapın.
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"]["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
            //    }
            //  }
            //}
        }
    }
}

JSON yükünün alt bölümleri serisini kaldırma

Aşağıdaki örnek, bir JSON ağacının alt bölümüne gitmek ve tek bir değerin, özel bir türün veya bu alt bölümde bir dizinin serisini kaldırmak için Jsonnode 'ın nasıl kullanılacağını gösterir.

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
        }
    }
}

JsonNode Ortalama sınıf örneği

Aşağıdaki örnek, tamsayı değerleri olan ve ortalama bir değeri hesaplayan bir JSON dizisi seçer:

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

namespace JsonNodeAverageGradeExample
{
    public class Program
    {
        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

Yukarıdaki kod:

  • Özelliği olan bir dizideki nesneler için Ortalama bir sınıf hesaplar Students Grade .
  • Bir sınıfa sahip olmayan öğrenciler için varsayılan bir 70 sınıfı atar.
  • Özelliğinden öğrencilerin sayısını alır Count JsonArray .

JsonDocument komutunu kullanma

Aşağıdaki örnek, JsonDocument BIR JSON dizesindeki verilere rastgele erişim için sınıfının nasıl kullanılacağını gösterir:

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

Yukarıdaki kod:

  • Analiz edilecek JSON 'in adlı bir dizede olduğunu varsayar jsonString .
  • Özelliği olan bir dizideki nesneler için Ortalama bir sınıf hesaplar Students Grade .
  • Bir sınıfa sahip olmayan öğrenciler için varsayılan bir 70 sınıfı atar.
  • , JsonDocument Uygulayan bir using ifadede örneği oluşturur JsonDocument IDisposable . Bir JsonDocument örnek atıldıktan sonra, tüm JsonElement örneklerine erişiminizi de kaybedersiniz. Bir örneğe erişimi sürdürmek için JsonElement , üst örnek atılmadan önce bunun bir kopyasını oluşturun JsonDocument . Bir kopya oluşturmak için çağrısı yapın JsonElement.Clone . Daha fazla bilgi için bkz. Jsondocument IDisposable.

Yukarıdaki örnek kod, her yinelemeyle bir değişkeni arttırarak öğrencileri sayar count . GetArrayLengthAşağıdaki örnekte gösterildiği gibi bir alternatif çağrdır:

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

Bu kodun işlediği JSON örneğine bir örnek aşağıda verilmiştir:

{
  "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
}

Yerine kullanan benzer bir örnek için JsonNode JsonDocument bkz. jsonnode Ortalama sınıf örneği.

Bir JsonDocument ve JsonElement öğelerini alt öğeler için arama

Üzerinde arama yapmak JsonElement , özelliklerde sıralı bir arama gerektirir ve bu nedenle nispeten düşüktür (örneğin, kullanırken TryGetProperty ). System.Text.Json Arama süresi yerine ilk ayrıştırma süresini en aza indirmek için tasarlanmıştır. Bu nedenle, bir nesnede arama yaparken performansı iyileştirmek için aşağıdaki yaklaşımları kullanın JsonDocument :

  • EnumerateArray EnumerateObject Kendi dizin oluşturma veya döngülerinizi yapmak yerine yerleşik numaralandırıcıları (ve) kullanın.
  • Kullanarak her bir özelliğin tamamında sıralı bir arama yapmayın JsonDocument RootElement . Bunun yerine, JSON verilerinin bilinen yapısına bağlı olarak iç içe geçmiş JSON nesnelerinde arama yapın. Örneğin, yukarıdaki kod örnekleri nesnelerde bir Grade özelliği arar Student Student ve Grade Özellikler için tüm nesneleri aramak yerine her biri için değerini elde edin JsonElement Grade . İkincisini yapmak, aynı verilerin üzerine gereksiz bir şekilde geçiş oluşmasına neden olur.

JsonDocumentJSON yazmak için kullanın

Aşağıdaki örnek, öğesinden nasıl JSON yazılacağını göstermektedir 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()

Yukarıdaki kod:

  • Bir JSON dosyasını okur, verileri bir JsonDocument dosyasına yükler ve bir dosyaya biçimli (düzgün yazdırılmış) JSON yazar.
  • JsonDocumentOptionsJSON girişi içindeki açıklamalara izin verildiğini ancak yok sayılacağını belirtmek için kullanır.
  • İşiniz bittiğinde, Flush Yazıcı üzerindeki çağrılar. Alternatif olarak, yazıcı bırakıldığında otomatik olarak temizlemeye izin verilir.

Örnek kod tarafından işlenecek JSON girişi örneği aşağıda verilmiştir:

{"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}

Sonuç, aşağıdaki düzgün yazdırılmış JSON çıktıdır:

{
  "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
}

JsonDocument, IDisposable

JsonDocument havuza alınmış arabellekte verilerin bellek içi bir görünümünü oluşturur. Bu nedenle, JsonDocument türü uygulanmıştır IDisposable ve bir blok içinde kullanılması gerekir using .

Yalnızca API 'nizden JsonDocument , yaşam süresi sahipliğini aktarmak ve arayan sorumluluğunu atmak istiyorsanız ' ı geri döndürün. Çoğu senaryoda, bu gerekli değildir. Çağıranın tüm JSON belgesi ile çalışması gerekiyorsa, Clone RootElement ' ın ' i döndürün JsonElement . Çağıranın JSON belgesi içinde belirli bir öğeyle çalışması gerekiyorsa, ' ın ' i döndürün Clone JsonElement . Ya da bir RootElement alt öğeyi doğrudan bir olmadan geri Clone döndürülürsünüz, çağıran, JsonElement JsonDocument kendisine ait olan öğesinden sonra döndürülen öğesine erişemez.

İşte şunları yapmanızı gerektiren bir örnek Clone :

public JsonElement LookAndLoad(JsonElement source)
{
    string json = File.ReadAllText(source.GetProperty("fileName").GetString());

    using (JsonDocument doc = JsonDocument.Parse(json))
    {
        return doc.RootElement.Clone();
    }
}

Yukarıdaki kod, bir özellik içeren bir için bekliyor JsonElement fileName . JSON dosyasını açar ve bir oluşturur JsonDocument . Yöntemi, çağıranın tüm belge ile çalışmak istediğini varsayar, bu yüzden öğesinin öğesini döndürür Clone RootElement .

Bir alır ve bir JsonElement alt öğe döndürüyorsa, alt öğenin bir kısmını döndürmek gerekli değildir Clone . Çağıran, JsonDocument geçirilen ' ın ait olduğu canlı tutmanın sorumluluğundadır JsonElement . Örnek:

public JsonElement ReturnFileName(JsonElement source)
{
   return source.GetProperty("fileName");
}

Utf8JsonWriter komutunu kullanma

Utf8JsonWriter , ve gibi ortak .NET türlerinden UTF-8 kodlu JSON metni yazmanın yüksek performanslı bir yoludur String Int32 DateTime . Yazıcı, özel serileştiriciler oluşturmak için kullanılabilen alt düzey bir türdür. JsonSerializer.SerializeYöntemi Utf8JsonWriter , kapakların altında kullanır.

Aşağıdaki örnek sınıfının nasıl kullanılacağını gösterir Utf8JsonWriter :

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)

UTF-8 metniyle yazma

Kullanırken en iyi performansı elde etmek için Utf8JsonWriter , WRITE JSON YÜKLERINI UTF-16 dizeleri yerıne UTF-8 ile kodlanmış olarak yazın. JsonEncodedTextBilinen dize özellik adlarını ve değerlerini sıra olarak önbelleğe almak ve önceden kodlamak için kullanın ve UTF-16 dize sabit değerleri kullanmak yerine yazıcıya geçirin. Bu, önbelleğe alma ve UTF-8 bayt dizilerini kullanmayla daha hızlıdır.

Özel kaçış yapmanız gerekiyorsa bu yaklaşım da geçerlidir. System.Text.Json bir dize yazarken kaçış özelliğini devre dışı bırakmanızı sağlar. Bununla birlikte, yazıcıya kendi özel JavaScriptEncoder bir seçenek olarak geçirebilirsiniz ya da JsonEncodedText kaçış yapmak için kendi uygulamanızı kullanarak kendi JavascriptEncoder öğesini oluşturabilir ve sonra JsonEncodedText dize yerine yazın. Daha fazla bilgi için bkz. karakter kodlamasını özelleştirme.

Ham JSON yaz

Bazı senaryolarda, ile oluşturmakta olduğunuz bir JSON yüküne "RAW" JSON yazmak isteyebilirsiniz Utf8JsonWriter . Utf8JsonWriter.WriteRawValueBunu yapmak için kullanabilirsiniz. Tipik senaryolar şunlardır:

  • Yeni JSON 'a eklemek istediğiniz mevcut bir JSON yüküyle sahipsiniz.

  • Değerleri varsayılan biçimlendirmeden farklı biçimlendirmek istiyorsunuz Utf8JsonWriter .

    Örneğin, sayı biçimlendirmesini özelleştirmek isteyebilirsiniz. Varsayılan olarak, System.Text.Json Örneğin değil, tam sayılar için ondalık noktayı atlar 1 1.0 . Korvaale daha az bayt yazmanın performans açısından iyi hale getirme alışkanlıktır. Ancak, JSON 'larınızın tüketicisinin sayıların Double olarak kabul edildiğini ve ondalık sayı olmayan sayıların tamsayı olduğunu varsayalım. Bir dizideki sayıların tümünün, tam sayılar için bir ondalık nokta yazarak ve sıfır olarak tanındığından emin olmak isteyebilirsiniz. Aşağıdaki örnek bunun nasıl yapılacağını göstermektedir:

    using System;
    using System.Collections.Generic;
    using System.IO;
    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
    //    }
    //  ]
    //}
    

Karakter kaçış 'yi özelleştirme

Stringescapehandling AYARı, JsonTextWriter ASCII olmayan tüm karakterleri veya HTML karakterlerinin kaçış seçeneklerini sunar. Varsayılan olarak, Utf8JsonWriter ASCII olmayan ve HTML karakterlerinin hepsini çıkar. Bu kaçış, derinlemesine savunma güvenlik nedenleriyle yapılır. Farklı bir kaçış ilkesi belirtmek için, oluşturun JavaScriptEncoder ve ayarlayın JsonWriterOptions.Encoder . Daha fazla bilgi için bkz. karakter kodlamasını özelleştirme.

Null değerleri yaz

Kullanarak null değerler yazmak için Utf8JsonWriter şunu çağırın:

  • WriteNull değer olarak null ile bir anahtar-değer çifti yazmak.
  • WriteNullValue JSON dizisinin bir öğesi olarak null yazmak için.

Dize özelliği için, dize null ise ve WriteString WriteStringValue WriteNull ile eşdeğerdir WriteNullValue .

TimeSpan, Uri veya Char değerlerini yaz

Timespan, Uri Veya değerlerini yazmak için char bunları dizeler olarak biçimlendirin ( ToString() Örneğin, çağırarak) ve çağırın WriteStringValue .

Utf8JsonReader komutunu kullanma

Utf8JsonReader , bir veya ' dan okunan UTF-8 kodlu JSON metin için yüksek performanslı, düşük bir ayırma, Salt ilet okuyucu olur ReadOnlySpan<byte> ReadOnlySequence<byte> . , Utf8JsonReader Özel Çözümleyicileri ve seri hale getiriciler oluşturmak için kullanılabilen alt düzey bir türdür. JsonSerializer.DeserializeYöntemi Utf8JsonReader , kapakların altında kullanır. Utf8JsonReaderVisual Basic koddan doğrudan kullanılamaz. daha fazla bilgi için bkz. Visual Basic desteği.

Aşağıdaki örnek sınıfının nasıl kullanılacağını gösterir Utf8JsonReader :

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

Yukarıdaki kod, jsonUtf8 DEĞIŞKENIN UTF-8 olarak kodlanmış GEÇERLI JSON içeren bir bayt dizisi olduğunu varsayar.

Kullanarak verileri filtreleme Utf8JsonReader

Aşağıdaki örnek, bir dosyanın zaman uyumlu olarak nasıl okunacağını gösterir ve bir değer arar.

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

Bu örneğin zaman uyumsuz bir sürümü için bkz. .net ÖRNEKLERI JSON projesi.

Yukarıdaki kod:

  • JSON 'un bir nesne dizisi içerdiğini ve her nesne dize türünde bir "ad" özelliği içerebildiği varsayılır.

  • "University" ile biten nesneleri ve "ad" özellik değerlerini sayar.

  • Dosyanın UTF-16 olarak kodlandığını varsayar ve bunu UTF-8 ' e dönüştürür. Aşağıdaki kod kullanılarak UTF-8 olarak kodlanmış bir dosya doğrudan bir ile okunabilir ReadOnlySpan<byte> :

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

    Dosya bir UTF-8 bayt sırası işareti (BOM) içeriyorsa, okuyucu metin gerektirdiğinden, baytları öğesine geçirmeden önce kaldırın Utf8JsonReader . Aksi takdirde, BOM geçersiz JSON olarak değerlendirilir ve okuyucu bir özel durum oluşturur.

Yukarıdaki kodun okuya, bir JSON örneği aşağıda verilmiştir. Sonuçtaki Özet ileti "2 ' den 4 ' ün" University "ile biten adlara sahiptir:

[
  {
    "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"
  }
]

Kullanarak akıştan okuma Utf8JsonReader

Büyük bir dosyayı (örneğin, boyutu bir gigabayt veya daha fazla) okurken, dosyanın tamamını aynı anda belleğe yükleme zorunluluğunu ortadan kaldırmak isteyebilirsiniz. Bu senaryo için bir kullanabilirsiniz FileStream .

Utf8JsonReaderBir akıştan okumak için kullanırken, aşağıdaki kurallar geçerlidir:

  • Kısmi JSON yükünün bulunduğu arabellek en az, onun içindeki en büyük JSON belirteci kadar büyük olmalıdır, böylece okuyucu ilerlemeye devam edebilir.
  • Arabellek en az JSON içindeki boşluk olan en büyük dizi kadar büyük olmalıdır.
  • Okuyucu, JSON yükünde bir sonrakini tamamen okuuncaya kadar okuduğu verileri takip etmez TokenType . Bu nedenle, arabellekte kalan baytlar varsa, bunları okuyucuya yeniden geçirmeniz gerekir. BytesConsumedKaç baytın kaldığını anlamak için kullanabilirsiniz.

Aşağıdaki kod bir akıştan nasıl okunacağını gösterir. Örnek bir gösterir MemoryStream . Benzer kod, FileStream FileStream Başlangıç AŞAMASıNDA bir UTF-8 bom içerdiğinde, ile birlikte çalışır. Bu durumda, kalan baytları öğesine geçirmeden önce bu üç baytı arabellekten çıkarmanız gerekir Utf8JsonReader . Aksi halde, BOM JSON 'ın geçerli bir parçası olarak kabul edilmediğinden okuyucu bir özel durum oluşturur.

Örnek kod, bir 4KB arabelleği ile başlar ve boyutun, bir bütün JSON belirtecine sığamayacak kadar büyük olmadığını bulduğu her bulduğunda, bu, okuyucunun JSON yükünde ilerlemesinin ilerlemesini sağlamak için gerekli olan her seferinde arabellek boyutunu iki katına çıkarır. Kod parçacığında belirtilen JSON örneği, yalnızca çok küçük bir başlangıç arabelleği boyutu ayarlarsanız (örneğin, 10 bayt) bir arabellek boyutunu tetikler. Başlangıçtaki arabellek boyutunu 10 olarak ayarlarsanız, Console.WriteLine deyimler arabellek boyutunun arttığı nedeni ve etkisini gösterir. 4 KB ilk arabellek boyutunda, tüm örnek JSON her biri tarafından gösterilir Console.WriteLine ve arabellek boyutunun hiçbir zaman artırılması gerekmez.

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

Yukarıdaki örnek, arabelleğin ne kadar büyüeceği hakkında sınır yoktur. Belirteç boyutu çok büyükse, kod bir OutOfMemoryException özel durumla başarısız olabilir. Bu, JSON 1 GB veya daha fazla boyuttaki bir belirteç içeriyorsa, 1 GB boyutunun, arabelleğe sığamayacak kadar büyük bir boyuta neden olduğundan bu durum oluşabilir int32 .

Utf8JsonReader bir başvuru yapısı

Utf8JsonReaderTür bir başvuru yapısı olduğundan, belirli sınırlamalarvardır. Örneğin, bir sınıf veya yapı üzerinde bir başvuru yapısı dışında bir alan olarak depolanamaz. Yüksek performans elde etmek için, bu tür bir ref struct başvuru yapısı olan giriş <byte> readonlyspan' i önbelleğe alma gerektirdiğinden bir olmalıdır. Ayrıca, bu tür durum taşıdığı için değişebilir olur. Bu nedenle, bunu değere göre değil başvuruya göre geçirin . Değere göre geçirmek bir yapı kopyasının oluşmasına neden olur ve durum değişiklikleri arayan tarafından görülemez. Başvuru yapıları kullanma hakkında daha fazla bilgi için bkz. Write Safe ve verimli C# kodu.

UTF-8 metnini oku

Kullanırken en iyi performansı elde etmek için Utf8JsonReader , UTF-16 dizeleri yerine zaten UTF-8 ile KODLANMıŞ JSON yüklerini okuyun. Kod örneği için bkz. Utf8JsonReader kullanarak filtre verileri.

Çok kesimli ReadOnlySequence ile oku

JSON girdisi Readonlyspan <byte> ise, ValueSpan okuma döngüsüne gittiğinizde her JSON öğesine okuyucudaki özellikten erişilebilir. Ancak, giriş, Readonlysequence <byte> ise (bir öğesinden okunması sonucu PipeReader ), bazı JSON öğeleri nesnenin birden fazla segmentine Straddle ReadOnlySequence<byte> . Bu öğelere ValueSpan , bir ardışık bellek bloğunun içinden erişilemez. Bunun yerine, giriş olarak çok bölgeli her seferinde, ReadOnlySequence<byte> HasValueSequence geçerli JSON öğesine nasıl erişebileceğinizi anlamak için okuyucudaki özelliği yoklayın. Önerilen bir model aşağıda verilmiştir:

while (reader.Read())
{
    switch (reader.TokenType)
    {
        // ...
        ReadOnlySpan<byte> jsonElement = reader.HasValueSequence ?
            reader.ValueSequence.ToArray() :
            reader.ValueSpan;
        // ...
    }
}

Özellik adı aramaları için ValueTextEquals kullanın

ValueSpanÖzellik adı aramalarını çağırarak bayt başına karşılaştırmalar yapmak için kullanmayın SequenceEqual . ValueTextEqualsBunun yerine çağırın, çünkü bu yöntem JSON 'da kaçan tüm karakterleri kaldırır. "Ad" adlı bir özelliğin nasıl aranacağını gösteren bir örnek aşağıda verilmiştir:

private static readonly byte[] s_nameUtf8 = Encoding.UTF8.GetBytes("name");
while (reader.Read())
{
    switch (reader.TokenType)
    {
        case JsonTokenType.StartObject:
            total++;
            break;
        case JsonTokenType.PropertyName:
            if (reader.ValueTextEquals(s_nameUtf8))
            {
                count++;
            }
            break;
    }
}

Null değerleri null yapılabilir değer türlerine oku

Yerleşik System.Text.Json API 'ler yalnızca null yapılamayan değer türleri döndürüyor. Örneğin, Utf8JsonReader.GetBoolean bir döndürür bool . JSON içinde bulursa bir özel durum oluşturur Null . Aşağıdaki örneklerde, bir tane null yapılabilir değer türü döndürerek ve bir tane varsayılan değeri döndürerek, null değerlerini işlemek için iki yol gösterilmektedir:

public bool? ReadAsNullableBoolean()
{
    _reader.Read();
    if (_reader.TokenType == JsonTokenType.Null)
    {
        return null;
    }
    if (_reader.TokenType != JsonTokenType.True && _reader.TokenType != JsonTokenType.False)
    {
        throw new JsonException();
    }
    return _reader.GetBoolean();
}
public bool ReadAsBoolean(bool defaultValue)
{
    _reader.Read();
    if (_reader.TokenType == JsonTokenType.Null)
    {
        return defaultValue;
    }
    if (_reader.TokenType != JsonTokenType.True && _reader.TokenType != JsonTokenType.False)
    {
        throw new JsonException();
    }
    return _reader.GetBoolean();
}

Ayrıca bkz.