Utf8JsonReader'ı kullanma System.Text.Json
Bu makalede, özel ayrıştırıcılar ve seri durumdan Utf8JsonReader çıkarıcılar oluşturmak için türünü nasıl kullanabileceğiniz gösterilmektedir.
Utf8JsonReader utf-8 ile kodlanmış JSON metni için yüksek performanslı, düşük ayırmalı, yalnızca ileriye dönük okuyucudur ve bir ReadOnlySpan<byte>
veya ReadOnlySequence<byte>
dosyasından okur. Utf8JsonReader
, özel ayrıştırıcılar ve seri durumdan çıkarıcılar oluşturmak için kullanılabilecek düşük düzeyli bir türüdür. JsonSerializer.Deserialize Yöntemler, kapakların altında kullanılırUtf8JsonReader
.
Utf8JsonReader
doğrudan Visual Basic kodundan kullanılamaz. Daha fazla bilgi için bkz . Visual Basic desteği.
Aşağıdaki örnekte sınıfın nasıl kullanılacağı gösterilmektedir 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://learn.microsoft.com/dotnet/standard/serialization/system-text-json-how-to#visual-basic-support
Yukarıdaki kod, değişkenin jsonUtf8
UTF-8 olarak kodlanmış geçerli JSON içeren bir bayt dizisi olduğunu varsayar.
Kullanarak verileri filtreleme Utf8JsonReader
Aşağıdaki örnekte, bir dosyanın zaman uyumlu bir şekilde nasıl okunduğu ve bir değerin nasıl aranduğu gösterilmektedir.
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://learn.microsoft.com/dotnet/standard/serialization/system-text-json-how-to#visual-basic-support
Bu örneğin zaman uyumsuz sürümü için bkz . .NET örnekleri JSON projesi.
Yukarıdaki kod:
JSON'un bir nesne dizisi içerdiğini ve her nesnenin dize türünde bir "name" özelliği içerebileceğini varsayar.
"Üniversite" ile biten nesneleri ve "name" özellik değerlerini sayar.
Dosyanın UTF-16 olarak kodlanmış olduğunu varsayar ve dosyayı UTF-8'e çevirir. UTF-8 olarak kodlanmış bir dosya, aşağıdaki kod kullanılarak doğrudan içinde
ReadOnlySpan<byte>
okunabilir:ReadOnlySpan<byte> jsonReadOnlySpan = File.ReadAllBytes(fileName);
Dosya bir UTF-8 bayt sipariş işareti (BOM) içeriyorsa, okuyucu metin beklediğinden baytları öğesine
Utf8JsonReader
geçirmeden önce dosyayı kaldırın. Aksi takdirde, BOM geçersiz JSON olarak kabul edilir ve okuyucu bir özel durum oluşturur.
Yukarıdaki kodun okuyabileceği bir JSON örneği aşağıda verilmiştır. Sonuçta elde edilen özet ileti "4'ün 2'sinde "Üniversite" ile biten adlar var" şeklindedir:
[
{
"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 bir akıştan okuma Utf8JsonReader
Büyük bir dosyayı (örneğin, gigabayt veya daha büyük boyutlu) okurken, dosyanın tamamını aynı anda belleğe yüklemek zorunda kalmamak isteyebilirsiniz. Bu senaryo için bir FileStreamkullanabilirsiniz.
bir akıştan okumak için kullanırken Utf8JsonReader
aşağıdaki kurallar geçerlidir:
- Okuyucunun ilerleme kaydedebilmesi için kısmi JSON yükünü içeren arabellek en az içindeki en büyük JSON belirteci kadar büyük olmalıdır.
- Arabellek en az JSON içindeki en büyük boşluk dizisi kadar büyük olmalıdır.
- Okuyucu, JSON yükünde bir sonrakini TokenType tamamen okuyana kadar okuduğu verileri izlemez. Bu nedenle, arabellekte kalan baytlar olduğunda, bunları okuyucuya yeniden geçirmeniz gerekir. Kaç bayt kaldığını belirlemek için kullanabilirsiniz BytesConsumed .
Aşağıdaki kodda bir akıştan nasıl okunduğu gösterilmektedir. Örnekte bir MemoryStreamgösterilir. Başlangıçta UTF-8 ürün reçetesi içermesi FileStream
dışında benzer kod ile FileStreamçalışır. Bu durumda, kalan baytları öğesine geçirmeden önce bu üç baytı Utf8JsonReader
arabellekten ayırmanız gerekir. Aksi takdirde, ürün reçetesi JSON'un geçerli bir parçası olarak kabul edilmediğinden okuyucu bir özel durum oluşturur.
Örnek kod 4 KB arabellekle başlar ve boyutun tam bir JSON belirtecine sığacak kadar büyük olmadığını her bulduğunda arabellek boyutunu iki katına çıkartır. Bu, okuyucunun JSON yükünde ileriye doğru ilerlemesi için gereklidir. Kod parçacığında sağlanan JSON örneği, yalnızca 10 bayt gibi çok küçük bir başlangıç arabellek boyutu ayarladığınızda arabellek boyutu artışı tetikler. İlk arabellek boyutunu 10 olarak ayarlarsanız, Console.WriteLine
deyimler arabellek boyutu artışlarının nedenini ve etkisini gösterir. 4 KB ilk arabellek boyutunda, örnek JSON'un tamamı her Console.WriteLine
biri tarafından gösterilir ve arabellek boyutunun hiçbir zaman artırılması gerekmez.
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://learn.microsoft.com/dotnet/standard/serialization/system-text-json-how-to#visual-basic-support
Yukarıdaki örnek, arabelleğin ne kadar büyüyebileceğiyle ilgili bir sınır ayarlamaz. Belirteç boyutu çok büyükse kod bir OutOfMemoryException özel durumla başarısız olabilir. JSON boyutu yaklaşık 1 GB veya daha büyük bir belirteç içeriyorsa bu durum oluşabilir çünkü 1 GB boyutu ikiye katlama, arabelleğe sığamayacak kadar büyük bir int32
boyuta neden olur.
başvuru yapısı sınırlamaları
Utf8JsonReader
Türü bir başvuru yapısı olduğundan, belirli sınırlamaları vardır. Örneğin, bir sınıf veya yapıda başvuru yapısı dışında bir alan olarak depolanamaz.
Yüksek performans elde etmek için bu tür bir ref struct
olmalıdır çünkü kendisi bir başvuru yapısı olan ReadOnlySpan<bayt> girişini önbelleğe alması gerekir. Buna ek olarak, Utf8JsonReader
durum barındırdığı için türü değişebilir. Bu nedenle, değere göre değil başvuruya göre geçirin. Değere göre geçirilmesi bir yapı kopyasına neden olur ve durum değişiklikleri çağıran tarafından görünmez.
Başvuru yapılarını kullanma hakkında daha fazla bilgi için bkz . Ayırmalardan kaçınma.
UTF-8 metnini okuma
kullanırken Utf8JsonReader
mümkün olan en iyi performansı elde etmek için, UTF-16 dizeleri yerine zaten UTF-8 metni olarak kodlanmış JSON yüklerini okuyun. Kod örneği için bkz . Utf8JsonReader kullanarak verileri filtreleme.
Çok segmentli ReadOnlySequence ile okuma
JSON girişiniz bir ReadOnlySpan<bayt> ise, okuma döngüsü boyunca her JSON öğesine okuyucudaki özelliğinden ValueSpan
erişilebilir. Ancak, girişiniz bir ReadOnlySequence<bayt> ise (bu, bir PipeReader'den okumanın sonucudur), bazı JSON öğeleri nesnenin birden çok kesimine ReadOnlySequence<byte>
karışabilir. Bu öğelere bitişik bir bellek bloğundan erişilemez ValueSpan . Bunun yerine, giriş olarak çok segmentli ReadOnlySequence<byte>
bir öğeniz olduğunda, geçerli JSON öğesine nasıl erişeceklerini öğrenmek için okuyucuda özelliğini yoklayın HasValueSequence . Önerilen desen aşağıdadır:
while (reader.Read())
{
switch (reader.TokenType)
{
// ...
ReadOnlySpan<byte> jsonElement = reader.HasValueSequence ?
reader.ValueSequence.ToArray() :
reader.ValueSpan;
// ...
}
}
Özellik adı aramaları için ValueTextEquals kullanma
Özellik adı aramalarını çağırarak SequenceEqual bayt bayt karşılaştırmaları yapmak için kullanmayınValueSpan. Bunun yerine çağırın ValueTextEquals çünkü bu yöntem, JSON'da kaçış yapılan tüm karakterlerin çıkışını çıkarır. "name" adlı bir özelliğin nasıl arandığı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 değer türlerine okuma
Yerleşik API'ler System.Text.Json
yalnızca null atanamayan değer türleri döndürür. Örneğin, Utf8JsonReader.GetBoolean bir bool
döndürür. JSON içinde bulursa Null
bir özel durum oluşturur. Aşağıdaki örneklerde, biri null değer türü döndürerek, diğeri varsayılan değeri döndürerek olmak üzere null değerleri işlemenin iki yolu 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();
}
Belirtecin alt öğelerini atla
Utf8JsonReader.Skip() Geçerli JSON belirtecinin alt öğelerini atlamak için yöntemini kullanın. Belirteç türü ise JsonTokenType.PropertyName, okuyucu özellik değerine geçer. Aşağıdaki kod parçacığında, okuyucuyu bir özelliğin değerine taşımak için kullanma Utf8JsonReader.Skip() örneği gösterilmektedir.
var weatherForecast = new WeatherForecast
{
Date = DateTime.Parse("2019-08-01"),
TemperatureCelsius = 25,
Summary = "Hot"
};
byte[] jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes(weatherForecast);
var reader = new Utf8JsonReader(jsonUtf8Bytes);
int temp;
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonTokenType.PropertyName:
{
if (reader.ValueTextEquals("TemperatureCelsius"))
{
reader.Skip();
temp = reader.GetInt32();
Console.WriteLine($"Temperature is {temp} degrees.");
}
continue;
}
default:
continue;
}
}
Kodu çözülen JSON dizelerini kullanma
.NET 7'den başlayarak, kodu çözülen bir JSON dizesi kullanmak yerine Utf8JsonReader.GetString() yöntemini kullanabilirsinizUtf8JsonReader.CopyString. sürümünden farklı olarak GetString(), her zaman yeni bir dize ayırır, CopyString boş dizeyi sahip olduğunuz bir arabelleğe kopyalamanıza olanak tanır. Aşağıdaki kod parçacığında kullanarak CopyStringUTF-16 dizesi kullanma örneği gösterilmektedir.
var reader = new Utf8JsonReader( /* jsonReadOnlySpan */ );
int valueLength = reader.HasValueSequence
? checked((int)reader.ValueSequence.Length)
: reader.ValueSpan.Length;
char[] buffer = ArrayPool<char>.Shared.Rent(valueLength);
int charsRead = reader.CopyString(buffer);
ReadOnlySpan<char> source = buffer.AsSpan(0, charsRead);
// Handle the unescaped JSON string.
ParseUnescapedString(source);
ArrayPool<char>.Shared.Return(buffer, clearArray: true);
void ParseUnescapedString(ReadOnlySpan<char> source)
{
// ...
}
İlgili API'ler
Bir örnekten özel bir türü seri durumdan
Utf8JsonReader
çıkarmak için veya JsonSerializer.Deserialize<TValue>(Utf8JsonReader, JsonTypeInfo<TValue>)çağrısında JsonSerializer.Deserialize<TValue>(Utf8JsonReader, JsonSerializerOptions) bulunur. Örnek için bkz . UTF-8'den seri durumdan çıkarma.JsonNode ve ondan türetilen sınıflar, değiştirilebilir bir DOM oluşturma olanağı sağlar. çağrısı JsonNode.Parse(Utf8JsonReader, Nullable<JsonNodeOptions>)yaparak bir
Utf8JsonReader
örneği'neJsonNode
dönüştürebilirsiniz. Aşağıdaki kod parçacığı bir örnek gösterir.using System.Text.Json; using System.Text.Json.Nodes; namespace Utf8ReaderToJsonNode { public class WeatherForecast { public DateTimeOffset Date { get; set; } public int TemperatureCelsius { get; set; } public string? Summary { get; set; } } public class Program { public static void Main() { var weatherForecast = new WeatherForecast { Date = DateTime.Parse("2019-08-01"), TemperatureCelsius = 25, Summary = "Hot" }; byte[] jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes(weatherForecast); var utf8Reader = new Utf8JsonReader(jsonUtf8Bytes); JsonNode? node = JsonNode.Parse(ref utf8Reader); Console.WriteLine(node); } } }
JsonDocument kullanarak
Utf8JsonReader
salt okunur bir DOM oluşturma olanağı sağlar. Bir örnekten JsonDocument.ParseValue(Utf8JsonReader) ayrıştırmakJsonDocument
Utf8JsonReader
için yöntemini çağırın. Yükü oluşturan JSON öğelerine türü aracılığıyla JsonElement erişebilirsiniz. kullanan JsonDocument.ParseValue(Utf8JsonReader)kodlar için bkz. RoundtripDataTable.cs ve deserialize inserialize inferred types to object properties içindeki kod parçacığı.Ayrıca, çağırarak JsonElement.ParseValue(Utf8JsonReader)belirli bir JsonElementJSON değerini temsil eden bir örneği olarak ayrıştırabilirsiniz
Utf8JsonReader
.