【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那里
案例二、转换器
自定义基本模式转换器 ,采用反射方式的序列化
- 将转换器类的实例添加到 JsonSerializerOptions.Converters 集合中。
- 将 [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 } ] } **//*/