【C# 序列化】 Utf8JsonReader和Utf8JsonWriter


簡介

【C# 序列化】 ReadOnlySequence<T>

JsonTokenType枚舉:定義組成JSON文本的各種JSON標志。例如startArray 表示 【 [】,  endArray表示【 ]】comment表示【//】,屬性名表示PropertyName

ref struct 是僅在堆棧上的值類型使用限制如下:  

  •      表現一個順序結構的布局;(譯注:可以理解為連續內存)
  •     只能在堆棧上使用。即用作方法參數和局部變量;
  •     不能用來聲明類或非 ref結構的靜態或實例成員;
  •     不能被本地函數捕獲或lambda表達式的方法參數;
  •     不能動態綁定、裝箱\拆箱。
  •     不能在異步方法、迭代器、數組、類型參數(泛型)中使用

ref struct也被稱為嵌入式引用。

ReadOnlySequence<Byte>:序列(英語:Sequences)在數學中是指被排成一列的對象或事件;例如,(C,Y,R)是一個字母的序列:順序是C第一,Y第二,R第三。序列可以是有限的(就像前面這個例子),也可以是無限的,就像所有正偶數的序列(2,4,6,...)。有限序列包含空序列(),它沒有元素。序列中的元素也稱為項,項的個數(可能是無限的)稱為序列的長度。序列寫作(a1,a2, ...)。簡單起見,也可以用符號(an)。有限的序列稱為列表(lists)。有限的字符串序列稱為字符串(string)。無限的序列稱為字符串流(stream)。
ReadOnlySequenceSegment<T>:

ReadOnlySpan<Byte>:高性能內存空間讀取數據結構。支持數組、list、字符竄。BytesConsumed:獲取到目前為止Utf8JsonReader實例消耗的總字節數。

Utf8JsonReader

屬性

CurrentDepth:獲取當前標記的深度。現狀后獲取Utf8JsonReader的當前狀態,並將其傳遞給Utf8JsonReader構造函數。
HasValueSequence:獲取一個值,該值指示要使用哪個value屬性來獲取令牌值。
IsFinalBlock:獲取Utf8JsonReader的這個實例的模式,該模式指示是否提供了所有的JSON數據,或者還有更多的數據。位置在提供的UTF-8編碼的輸入ReadOnlySequence中獲取當前的SequencePosition;如果Utf8JsonReader結構體是用ReadOnlySpan構造的,則獲取默認的SequencePosition。
TokenStartIndex:獲取最后一個已處理的JSON令牌開始的索引(在給定UTF-8編碼的輸入文本中),跳過任何空格。
TokenType:獲取UTF-8編碼的JSON文本中最后處理的JSON標志的類型。
ValueSequence:僅當標志包含在多個段中時,獲取作為輸入負載的ReadOnlySequence片的最后處理標志的原始值。
ValueSpan:如果標志適合單個段,或者如果讀取器是用ReadOnlySpan中包含的JSON有效載荷構造的,則獲取作為輸入有效載荷的ReadOnlySpan片的最后處理令牌的原始值。

 主要方法

Get基礎數據類型() :獲取當前token的數據格式。
GetComment() :獲取注釋
GetGuid():
GetDateTimeOffset
Read():讀取一個Token
Skip:跳過

實戰案例

案例一、Read()+TokenType+TokenStartIndex

在項目目錄下新建文件“sample.json”,輸入以下信息然后保存

{
"postTitle":"Programming",
"language":"C#",
"author":{
    "firstName":"Nick " ,
    "lastName ":"Carter"
            },
"publishedAt":"2019-10-22T20:50:21.000Z",
"wordCount":13435,
"isoriginal": true,
"tags":[ "C#","JSON API",".NET Core"]
}

代碼如下

var sampleJson= File.ReadAllBytes("sample.json").AsSpan();
Utf8JsonReader reader=new Utf8JsonReader(sampleJson);
while (reader.Read())//reader就會移動到JSON數據里面的下一個Token那里
{
    string item = SwitchToken(reader);
    if (reader.TokenType==JsonTokenType.PropertyName)
    {
        string startIndex = reader.TokenStartIndex.ToString();//token 開始字符為止
        Console.Write(startIndex   + item + ":"  );
    }
    else { Console.WriteLine(item); }
    Console.WriteLine(reader.CurrentDepth);
    Console.WriteLine(reader.CurrentState);
}

string SwitchToken(Utf8JsonReader reader) =>
    reader.TokenType switch
    {
        JsonTokenType .StartObject=> "{",
        JsonTokenType.EndObject => "}",
        JsonTokenType.StartArray => "[",
        JsonTokenType.EndArray => "]",
        JsonTokenType.False => $"{reader.GetBoolean()}," ,
        JsonTokenType.PropertyName =>$@"""{ reader.GetString()!}""",

        JsonTokenType.True => $"{reader.GetBoolean()}," ,
        JsonTokenType.Number => $"{reader.GetInt32()}," ,

        JsonTokenType.String => @$"""{reader.GetString()}"","  ,
        JsonTokenType.Null=> "Null",
        _ => "None",
    };

 

【解說】

Main方法里面,我們使用File.ReadAllBytes從sample.json文件讀取數格式為byte[],然后通過AsSpan這個擴展方法將其轉化為Span<byte>數據類型,然后把它傳遞到 Utf8JsonReader 的構造函數來創建一個JSON的reader。
接下來使用while循環對JSON數據的每個Token進行讀取,每次執行Read()方法時,reader就會移動到JSON數據里面的下一個Token那里

 

案例二、轉換器

自定義基本模式轉換器 ,采用反射方式的序列化

  1. 將轉換器類的實例添加到 JsonSerializerOptions.Converters 集合中。
  2. 將 [JsonConverter] 特性應用於需要自定義轉換器的屬性或者將 [JsonConverter] 屬性應用於表示自定義值類型的類或結構。
JsonSerializerOptions op = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    Converters = { new MYEnumToUpperStingConverter() },//將轉換器類的實例添加到 JsonSerializerOptions.Converters 集合中。

    WriteIndented = true,
};

WeatherForecastWithEnum wf=new WeatherForecastWithEnum();   
string wfw= JsonSerializer.Serialize(wf, op);
WeatherForecastWithEnum wff=JsonSerializer.Deserialize<WeatherForecastWithEnum>(wfw,op);
Console.WriteLine( wfw);
public class MYEnumToUpperStingConverter : JsonConverter<Summary>
{

    public override Summary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return (Summary)Enum.Parse(typeToConvert, reader.GetString());
    }

    public override void Write(Utf8JsonWriter writer, Summary value, JsonSerializerOptions options)
    {
        writer.WriteStringValue( Enum.GetName(value));
    }
}


public class WeatherForecastWithEnum
{
   
    public DateTimeOffset Date { get; set; } = DateTime.Now;
    public int TemperatureCelsius { get; set; } = new Random().Next(1000);

    [JsonConverter(typeof(MYEnumToUpperStingConverter))]//將 [JsonConverter] 特性應用於需要自定義轉換器的屬性。
    public Summary Summaryp { get; set; } = Summary.Cold;

    [JsonConverter(typeof(MYEnumToUpperStingConverter))]
    public Summary Summaryp2 { get; set; } = Summary.Cold;
}

public enum Summary
{
    Cold, Cool, Warm, Hot
}

 Utf8JsonWriter

 綜合應用  采用反射方式的序列化

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace WriteRawJson
{
    public class Program
    {/*w  w    w  .  de    mo    2 s   .c  o    m*/
        public static void Main()
        {
            JsonWriterOptions writerOptions = new() { Indented = true, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
            using MemoryStream stream = new();
            using Utf8JsonWriter writer = new(stream, writerOptions);
            writer.WriteStartObject();

            // writer.WritePropertyName("defaultJsonFormatting");
            // writer.WriteStartArray();
            //or
            writer.WriteStartArray("defaultJsonFormatting");

            foreach (double number in new double[] { 50.4, 51 })
            {
                writer.WriteStartObject();

                writer.WritePropertyName("value");
                writer.WriteNumberValue(number);

                writer.WriteNull("Wait");// "Wait": null
                //or
                writer.WritePropertyName("Wait2");// "Wait2": null
                writer.WriteNullValue();

                writer.WriteString("WriteString", "dsfsdf");
                //or
                writer.WritePropertyName("WriteString1");// "Wait2": null
                writer.WriteStringValue("value");

                writer.WriteCommentValue("Comment");// 注釋/*Comment*/
                writer.WriteEndObject();
            }
            writer.WriteEndArray();
            writer.WriteStartArray("customJsonFormatting");
            foreach (double result in new double[] { 50.4, 51 })
            {
                writer.WriteStartObject();
                writer.WritePropertyName("value");
                writer.WriteRawValue( //  驗證輸入是否為符合 RFC 8259 的 JSON 
                    FormatNumberValue(result), skipInputValidation: true);
                writer.WriteEndObject();
            }
            writer.WriteEndArray();
            writer.WriteEndObject();
            writer.Flush();
            string json = Encoding.UTF8.GetString(stream.ToArray());

            Console.WriteLine(json);
            JsonSerializerOptions options = new JsonSerializerOptions { ReadCommentHandling = JsonCommentHandling.Skip };// 跳過注釋
            Rootobject rootobject = JsonSerializer.Deserialize<Rootobject>(json, options);

        }
        static string FormatNumberValue(double numberValue)
        {
            return numberValue == Convert.ToInt32(numberValue) ?
                numberValue.ToString() + ".0" : numberValue.ToString();
        }
    }

    //拷貝Jsonstring 然后選擇菜單 【編輯】>選擇性粘貼>將Json粘貼為類
    public class Rootobject
    {
        public Defaultjsonformatting[] defaultJsonFormatting { get; set; }
        public Customjsonformatting[] customJsonFormatting { get; set; }
    }

    public class Defaultjsonformatting
    {
        public float value { get; set; }
        public object Wait { get; set; }
        public object Wait2 { get; set; }
        public string WriteString { get; set; }
        public string WriteString1 { get; set; }
    }

    public class Customjsonformatting
    {
        public float value { get; set; }
    }


}
/*輸出:
    {
  "defaultJsonFormatting": [
    {
      "value": 50.4,
      "Wait": null,
      "Wait2": null,
      "WriteString": "dsfsdf",
      "WriteString1": "value"
      /*Comment*//*
    },
    {
    "value": 51,
      "Wait": null,
      "Wait2": null,
      "WriteString": "dsfsdf",
      "WriteString1": "value"
     /*Comment*//*
    }
  ],
  "customJsonFormatting": [
    {
      "value": 50.4
    },
    {
    "value": 51.0
    }
  ]
}
**//*/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM