Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makalede, özel ayrıştırıcılar ve deserileştiriciler oluşturmak için Utf8JsonReader 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 bir okuyucudur. Metin bir ReadOnlySpan<byte> veya ReadOnlySequence<byte>'den okunur.
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ürdür. (Yöntemler, JsonSerializer.Deserialize perde arkasında Utf8JsonReader kullanır.)
Aşağıdaki örnekte sınıfının nasıl kullanılacağı gösterilmektedir Utf8JsonReader . Bu kod, değişkenin jsonUtf8Bytes UTF-8 olarak kodlanmış geçerli JSON içeren bir bayt dizisi olduğunu varsayar.
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
Not
Utf8JsonReader doğrudan Visual Basic kodundan kullanılamaz. Daha fazla bilgi için bkz . Visual Basic desteği.
Utf8JsonReader kullanarak verileri filtreleme
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
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
ReadOnlySpan<byte>içine okunabilir.ReadOnlySpan<byte> jsonReadOnlySpan = File.ReadAllBytes(fileName);Dosya bir UTF-8 bayt sipariş işareti (BOM) içeriyorsa, okuyucu metin beklediği için baytları
Utf8JsonReaderöğesine geçirmeden önce bu işareti kaldırın. Aksi takdirde, BOM geçersiz JSON olarak kabul edilir ve okuyucu bir istisna fırlatır.
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"
}
]
İpucu
Bu örneğin zaman uyumsuz sürümü için bkz . .NET örnekleri JSON projesi.
Utf8JsonReader kullanarak bir akıştan okuma.
Büyük bir dosyayı (örneğin, gigabayt veya daha büyük boyutlu) okurken, dosyanın tamamını aynı anda belleğe yüklemekten kaçınmak isteyebilirsiniz. Bu senaryo için bir FileStreamkullanabilirsiniz.
Utf8JsonReader ile bir akıştan okuma yapılırken 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ündeki bir sonraki TokenType tamamen okunana 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. Benzer kod FileStream ile çalışır, ancak FileStream başlangıçta bir UTF-8 BOM içeriyorsa çalışmaz. Bu durumda, geri kalan baytları Utf8JsonReader öğesine geçirmeden önce bu üç baytı arabellekten çıkarmanız gerekir. Aksi takdirde, BOM JSON'un geçerli bir parçası olarak kabul edilmediğinden okuyucu bir hata 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 başlangıç arabellek boyutunda, örnek JSON'un tamamı, Console.WriteLine yapılan her çağrıda gösterilir ve arabellek boyutunun artırılmasına asla gerek kalmaz.
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 durum nedeniyle başarısız olabilir. JSON verisi, boyutu yaklaşık 1 GB veya daha büyük olan bir belirteç içeriyorsa bu durum oluşabilir, çünkü 1 GB boyutunu ikiye katlamak, arabelleğe sığamayacak kadar büyük bir int32 boyutuna yol açar.
ref yapı sınırlamaları
Utf8JsonReader türü bir ref structolduğundan, belirli sınırlamaları vardır. Örneğin, ref struct dışında bir sınıf veya yapıda alan olarak depolanamaz.
Yüksek performans elde etmek için, Utf8JsonReader, girişin ReadOnlySpan<byte> (ki kendisi de bir ref struct) önbelleğe alınması gerektiğinden bir ref struct olmalıdır. Buna ek olarak, Utf8JsonReader durum barındırdığı için türü değişebilir. Bu nedenle, değere göre değil referansa göre geçirin. Değer olarak Utf8JsonReader'nin geçirilmesi, bir yapı kopyası oluşturur ve durum değişiklikleri çağıran tarafından fark edilmez.
Başvuru yapılarını kullanma hakkında daha fazla bilgi için "Ayırmalardan kaçınma" bölümüne bkz
UTF-8 metnini okuma
kullanırken Utf8JsonReadermü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<byte> ise, her JSON öğesine okuma döngüsü sırasında okuyucunun ValueSpan özelliği aracılığıyla erişilebilir. Ancak, girişiniz bir ReadOnlySequence<byte> ise (bu, bir PipeReader'den okumanın sonucudur), bazı JSON öğeleri nesnenin birden çok segmentine ReadOnlySequence<byte> yayılabilir. Bu öğelere ValueSpan içinde bitişik bir bellek bloğundan erişilemez. Bunun yerine, giriş olarak çok segmentli ReadOnlySequence<byte> bir öğeniz olduğunda, okuyucuda HasValueSequence özelliğini sorgulayarak geçerli JSON elemanına nasıl erişileceğini belirleyin. Önerilen desen aşağıdadır:
while (reader.Read())
{
switch (reader.TokenType)
{
// ...
ReadOnlySpan<byte> jsonElement = reader.HasValueSequence ?
reader.ValueSequence.ToArray() :
reader.ValueSpan;
// ...
}
}
Birden çok JSON belgesini okuma
.NET 9 ve sonraki sürümlerinde, tek bir arabellekten veya akıştan birden çok boşlukla ayrılmış JSON belgesini okuyabilirsiniz. Varsayılan olarak, Utf8JsonReader ilk üst düzey belgenin sonunda boşluk olmayan karakterler algılarsa bir özel durum oluşturur. Ancak, bayrağını JsonReaderOptions.AllowMultipleValues kullanarak bu davranışı yapılandırabilirsiniz.
JsonReaderOptions options = new() { AllowMultipleValues = true };
Utf8JsonReader reader = new("null {} 1 \r\n [1,2,3]"u8, options);
reader.Read();
Console.WriteLine(reader.TokenType); // Null
reader.Read();
Console.WriteLine(reader.TokenType); // StartObject
reader.Skip();
reader.Read();
Console.WriteLine(reader.TokenType); // Number
reader.Read();
Console.WriteLine(reader.TokenType); // StartArray
reader.Skip();
Console.WriteLine(reader.Read()); // False
AllowMultipleValues olarak ayarlandığındatrue, JSON'ı geçersiz JSON'un sonundaki verileri içeren yüklerden de okuyabilirsiniz.
JsonReaderOptions options = new() { AllowMultipleValues = true };
Utf8JsonReader reader = new("[1,2,3] <NotJson/>"u8, options);
reader.Read();
reader.Skip(); // Succeeds.
reader.Read(); // Throws JsonReaderException.
Birden çok üst düzey değerin akışını yapmak için DeserializeAsyncEnumerable<TValue>(Stream, Boolean, JsonSerializerOptions, CancellationToken) veya DeserializeAsyncEnumerable<TValue>(Stream, JsonTypeInfo<TValue>, Boolean, CancellationToken) overload’u kullanın. Varsayılan olarak, DeserializeAsyncEnumerable tek bir en üst düzey JSON dizisinde yer alan öğelerin akışını yapmaya çalışır.
true geçerek birden çok üst düzey değerin akışını sağlamak için topLevelValues parametresini kullanın.
ReadOnlySpan<byte> utf8Json = """[0] [0,1] [0,1,1] [0,1,1,2] [0,1,1,2,3]"""u8;
using var stream = new MemoryStream(utf8Json.ToArray());
var items = JsonSerializer.DeserializeAsyncEnumerable<int[]>(stream, topLevelValues: true);
await foreach (int[] item in items)
{
Console.WriteLine(item.Length);
}
/* This snippet produces the following output:
*
* 1
* 2
* 3
* 4
* 5
*/
Özellik adı sorgulamaları
Özellik adlarını aramak için ValueSpan'yi kullanarak bayt bayt karşılaştırmalar yapmayınSequenceEqual çağırarak. Bunun yerine çağrısı ValueTextEqualsyapın çünkü bu yöntem, JSON'da kaçış yapılan tüm karakterlerin çıkışını kaldırıyor. "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 System.Text.Json API'ler yalnızca null atanamayan değer türlerini döndürür. Örneğin, Utf8JsonReader.GetBoolean bir booldöndürür. JSON içinde Null bulursa bir istisna atar. 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();
}
Token alt öğelerini atla
Utf8JsonReader.Skip() yöntemini, geçerli JSON belirtecinin alt öğelerini atlamak için 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;
}
}
Çözümlenmiş JSON dizelerini tüketme
.NET 7'den başlayarak, kodu çözülen bir JSON dizesi kullanmak için Utf8JsonReader.GetString() yerine Utf8JsonReader.CopyString yöntemini kullanabilirsiniz. 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 CopyString kullanarak bir UTF-16 dizgisinin nasıl tüketileceğine ilişkin bir örnek 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
Özel bir türü
Utf8JsonReaderörneğinden serileştirmeden çıkarmak için JsonSerializer.Deserialize<TValue>(Utf8JsonReader, JsonSerializerOptions) veya JsonSerializer.Deserialize<TValue>(Utf8JsonReader, JsonTypeInfo<TValue>) çağırın. Örnek için bkz UTF-8'den serisi kaldırma.JsonNode ve ondan türetilen sınıflar, değiştirilebilir bir DOM oluşturma olanağı sağlar. JsonNode.Parse(Utf8JsonReader, Nullable<JsonNodeOptions>) çağrısını
Utf8JsonReaderyaparak birJsonNodeörneğine 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 salt okunur bir DOM oluşturma olanağı sağlar. JsonDocument.ParseValue(Utf8JsonReader) yöntemini bir
Utf8JsonReaderörneğindenJsonDocumentayrıştırmak için ç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 inferred türlerini nesne özelliklerine seriletişim içinde yer alan kod parçacığı.Ayrıca, bir
Utf8JsonReaderörneğini belirli bir JsonElement JSON değerini temsil edecek şekilde JsonElement.ParseValue(Utf8JsonReader) çağrısını yaparak ayrıştırabilirsiniz.