Az Utf8JsonReader használata System.Text.Json
Ez a cikk bemutatja, hogyan használhatja a típust Utf8JsonReader egyéni elemzők és deszerializálók készítéséhez.
Utf8JsonReader az UTF-8 kódolt JSON-szövegek nagy teljesítményű, alacsony kiosztású, előre csak továbbítható olvasója, amely egy ReadOnlySpan<byte>
vagy ReadOnlySequence<byte>
. Ez Utf8JsonReader
egy alacsony szintű típus, amely egyéni elemzők és deszerializálók készítésére használható. A JsonSerializer.Deserialize módszerek a fedelek alatt használhatók Utf8JsonReader
.
Utf8JsonReader
nem használható közvetlenül a Visual Basic-kódból. További információ: Visual Basic-támogatás.
Az alábbi példa az osztály használatát Utf8JsonReader mutatja be:
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
Az előző kód feltételezi, hogy a jsonUtf8
változó egy érvényes JSON-t tartalmazó bájttömb, amely UTF-8 kóddal van kódolva.
Adatok szűrése Utf8JsonReader
Az alábbi példa bemutatja, hogyan olvashatja el szinkron módon a fájlokat, és hogyan kereshet értékeket.
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
A példa aszinkron verzióját a .NET-minták JSON-projektje tartalmazza.
A fenti kód a következőket végzi el:
Feltételezi, hogy a JSON objektumtömböt tartalmaz, és minden objektum tartalmazhat egy "name" típusú tulajdonságot.
Megszámolja az "Egyetem" végződésű objektumokat és "name" tulajdonságértékeket.
Feltételezi, hogy a fájl UTF-16-ként van kódolva, és UTF-8-ra kódolja. Az UTF-8 kóddal kódolt fájlok közvetlenül beolvashatók egy
ReadOnlySpan<byte>
fájlba a következő kóddal:ReadOnlySpan<byte> jsonReadOnlySpan = File.ReadAllBytes(fileName);
Ha a fájl UTF-8 bájtos rendelésjelet (BOM) tartalmaz, távolítsa el, mielőtt a bájtokat átadta volna a
Utf8JsonReader
fájlnak, mivel az olvasó szöveget vár. Ellenkező esetben a BOM érvénytelen JSON-nak minősül, és az olvasó kivételt jelez.
Íme egy JSON-minta, amelyet az előző kód képes olvasni. Az eredményként kapott összefoglaló üzenet a következő: "4-ből 2 neve "Egyetem" végződésű:
[
{
"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"
}
]
Olvasás streamből a következő használatával: Utf8JsonReader
Nagy méretű (például gigabájt méretű) fájlok olvasása esetén érdemes lehet elkerülni, hogy a teljes fájlt egyszerre töltse be a memóriába. Ebben a forgatókönyvben használhat egy FileStream.
Utf8JsonReader
Streamből való olvasáskor a következő szabályok érvényesek:
- A részleges JSON hasznos adatokat tartalmazó puffernek legalább olyan nagynak kell lennie, mint a legnagyobb JSON-jogkivonat, hogy az olvasó előrehaladjon.
- A puffernek legalább akkora méretűnek kell lennie, mint a legnagyobb szabad terület a JSON-ban.
- Az olvasó nem követi nyomon az általa beolvasott adatokat, amíg teljesen be nem olvassa a következőt TokenType a JSON hasznos adatai között. Így ha a pufferben bájtok vannak hátra, újra át kell adnia őket az olvasónak. Megadhatja BytesConsumed , hogy hány bájt maradjon hátra.
Az alábbi kód bemutatja, hogyan olvashat egy streamből. A példa egy MemoryStream. A hasonló kód egy FileStreamUTF-8-ás anyagjegyzéket tartalmaz az elején, kivéve, ha az FileStream
UTF-8 BOM-ot tartalmaz. Ebben az esetben a fennmaradó bájtok továbbítása előtt a pufferből le kell csíkolnia Utf8JsonReader
ezt a három bájtot. Ellenkező esetben az olvasó kivételt vetne ki, mivel a BOM nem tekinthető a JSON érvényes részének.
A mintakód egy 4 KB-os pufferrel kezdődik, és minden alkalommal megduplázza a pufferméretet, amikor megállapítja, hogy a méret nem elég nagy ahhoz, hogy elférjen egy teljes JSON-jogkivonatban, ami ahhoz szükséges, hogy az olvasó előrehaladjon a JSON hasznos adatain. A kódrészletben megadott JSON-minta csak akkor aktiválja a pufferméret növelését, ha nagyon kis kezdeti pufferméretet állít be, például 10 bájtot. Ha a kezdeti pufferméretet 10-esre állítja, az utasítások a Console.WriteLine
pufferméret növekedésének okát és hatását szemléltetik. A 4 KB kezdeti pufferméretnél a teljes JSON-minta látható mindegyiknél Console.WriteLine
, és a pufferméretet soha nem kell növelni.
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
Az előző példa nem állít be korlátot a puffer méretének növekedésére. Ha a jogkivonat mérete túl nagy, a kód kivétellel OutOfMemoryException meghiúsulhat. Ez akkor fordulhat elő, ha a JSON legalább 1 GB méretű jogkivonatot tartalmaz, mivel az 1 GB-os méret megduplázása olyan méretet eredményez, amely túl nagy ahhoz, hogy beleférjen egy int32
pufferbe.
ref struct korlátozások
Mivel a Utf8JsonReader
típus ref struct, bizonyos korlátozásokkal rendelkezik. Például nem tárolható mezőként egy osztályban, és nem lehet más struktúraként tárolni, mint egy átfstruktúra.
A nagy teljesítmény eléréséhez ennek a típusnak egy olyan típusnak kell lennie ref struct
, mivel gyorsítótárazza a bemeneti ReadOnlySpan<bájtot>, amely maga is egy refstruct. Emellett a Utf8JsonReader
típus nem módosítható, mivel állapotot tartalmaz. Ezért ne érték, hanem hivatkozás útján adja át. Ha érték szerint adja át, az strukturált példányt eredményez, és az állapotváltozások nem lesznek láthatók a hívó számára.
Az újrafstrukturálások használatáról további információt a foglalások elkerülése című témakörben talál.
UTF-8 szöveg olvasása
Ha a lehető legjobb teljesítményt szeretné elérni használat Utf8JsonReader
közben, olvassa el az UTF-16 sztringek helyett már UTF-8 szövegként kódolt JSON-hasznos adatokat. Példakód : Adatok szűrése az Utf8JsonReader használatával.
Olvasás többszegmensű ReadOnlySequence használatával
Ha a JSON-bemenet egy ReadOnlySpan<bájt>, minden JSON-elem elérhető az ValueSpan
olvasó tulajdonságából, miközben végighalad az olvasási cikluson. Ha azonban a bemenet egy ReadOnlySequence bájt<> (amely egy PipeReaderolvasás eredménye), egyes JSON-elemek az objektum több szegmensét ReadOnlySequence<byte>
is áttehetik. Ezek az elemek nem érhetők el egy összefüggő memóriablokkból ValueSpan . Ehelyett, ha több szegmenst ReadOnlySequence<byte>
használ bemenetként, lekérdezi az HasValueSequence olvasó tulajdonságát, hogy megtudja, hogyan érheti el az aktuális JSON-elemet. Íme egy ajánlott minta:
while (reader.Read())
{
switch (reader.TokenType)
{
// ...
ReadOnlySpan<byte> jsonElement = reader.HasValueSequence ?
reader.ValueSequence.ToArray() :
reader.ValueSpan;
// ...
}
}
ValueTextEquals használata tulajdonságnév-keresésekhez
Ne használjon ValueSpan bájtonkénti összehasonlítást a tulajdonságnév-keresések meghívásával SequenceEqual . Hívjon ValueTextEquals inkább, mert ez a metódus felfedi a JSON-ban megszabadult karaktereket. Íme egy példa, amely bemutatja, hogyan kereshet egy "name" nevű tulajdonságot:
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 értékek beolvasása null értékű értéktípusokba
A beépített System.Text.Json
API-k csak nem null értékű értéktípusokat ad vissza. Például egy Utf8JsonReader.GetBooleanbool
. Kivételt eredményez, ha a JSON-ban talál Null
. Az alábbi példák két módszert mutatnak be a null értékek kezelésére, az egyik a null értékű típus visszaadásával, a másik pedig az alapértelmezett érték visszaadásával:
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 gyermekeinek kihagyása
Utf8JsonReader.Skip() A metódus használatával kihagyhatja az aktuális JSON-jogkivonat gyermekeit. Ha a jogkivonat típusa az JsonTokenType.PropertyName, az olvasó a tulajdonságértékre lép. Az alábbi kódrészlet egy példát Utf8JsonReader.Skip() mutat be arra, hogy az olvasót egy tulajdonság értékére kell áthelyezni.
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;
}
}
Dekódolt JSON-sztringek felhasználása
A .NET 7-től kezdve használhatja a metódust ahelyett Utf8JsonReader.CopyStringUtf8JsonReader.GetString() , hogy dekódolt JSON-sztringet használ. Ellentétben GetString()az új sztringgel, amely mindig lefoglal egy új sztringet, CopyString lehetővé teszi a le nem ágyazott sztring másolását egy saját pufferbe. Az alábbi kódrészlet egy UTF-16 sztring CopyStringhasználatát szemlélteti.
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)
{
// ...
}
Kapcsolódó API-k
Egyéni típus deszerializálása példányból, hívásból
Utf8JsonReader
JsonSerializer.Deserialize<TValue>(Utf8JsonReader, JsonSerializerOptions) vagy JsonSerializer.Deserialize<TValue>(Utf8JsonReader, JsonTypeInfo<TValue>). Példa: Deserialize from UTF-8.JsonNode és az abból származó osztályok lehetővé teszik egy mutable DOM létrehozását. A példányokat
Utf8JsonReader
hívással JsonNode.Parse(Utf8JsonReader, Nullable<JsonNodeOptions>)konvertálhatja egy példánysáJsonNode
. Az alábbi kódrészlet egy példát mutat be.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 lehetővé teszi, hogy írásvédett DOM-ot hozzon létre a
Utf8JsonReader
. Hívja meg a JsonDocument.ParseValue(Utf8JsonReader) metódust egy példány elemzéséhezJsonDocument
Utf8JsonReader
. A hasznos adatokat alkotó JSON-elemeket a típuson keresztül érheti JsonElement el. Például a használt JsonDocument.ParseValue(Utf8JsonReader)kód, lásd a RoundtripDataTable.cs és a kódrészletet a Deserialize inferred types to object properties (Az objektumtulajdonságok deszerializálása) című témakörben.Egy adott JSON-értéket képviselő példányt
Utf8JsonReader
JsonElementis elemezhet hívással JsonElement.ParseValue(Utf8JsonReader).
Lásd még
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: