文档知识库教程OpenHarmony【免费下载链接】CangjieCorpus本仓库为仓颉编程语言语料库聚焦 仓颉编程语言 核心知识体系整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源经结构化处理与专业标注构建为支持 RAG检索增强生成技术 的高质量知识基座适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用推动鸿蒙开发生态智能化升级项目地址https://gitcode.com/Cangjie/CangjieCorpus点击查看免费下载本指南面向仓颉Cangjie开发者系统讲解扩展库stdx.encoding.json.stream包中JsonReader、JsonWriter两个核心类以及配套的JsonToken枚举、JsonDeserializable/JsonSerializable接口和WriteConfig配置结构体。文章基于本仓库 json_stream_package_api 下的官方 API 文档编写结合示例代码与std/stdx源码佐证帮助你掌握流式读取、逐 token 反序列化、链式写入、输出格式控制等完整实战能力。一、包定位对象与 JSON 数据流之间的双向转换json.stream包全名stdx.encoding.json.stream主要用于仓颉对象与 JSON 数据流之间的互相转换是仓颉标准库stdx.encoding.json之外针对流式处理场景提供的专门方案。二者的区别在于encoding.json 包 侧重于把 JSON 文本解析为JsonValue/DataModel这种内存树状模型适合整体加载、查询修改后再整体输出的场景encoding.json.stream 包 则面向逐 token 的流式解析与流式写出数据可以来自文件、网络、内存缓冲区等任意InputStream/OutputStream不需要把整个 JSON 一次性载入内存。从 包依赖表 可以看到import stdx.encoding.json.stream.*只依赖stdx.encoding.json.stream自身一个扩展库且不随编译器、工具链一起发布需要单独下载 stdx 二进制包后通过cjc -L $CANGJIE_STDX_PATH -lstdx.encoding.json.stream链接用 cjpm 构建则无需手工处理链接顺序。包内公开的核心构件如下表所示构件名称作用类JsonReader从InputStream读取 JSON 数据流反序列化为仓颉对象类JsonWriter将仓颉对象序列化后写入OutputStream枚举JsonToken标识 JSON 流中结构、名称或值类型配合peek()做分派接口JsonDeserializableT自定义类型反序列化的入口静态fromJson接口JsonSerializable自定义类型序列化的入口实例方法toJson结构体WriteConfigJsonWriter的输出格式配置紧凑/美化/缩进/换行等二、JsonReader流式反序列化的逐 token 读取模型2.1 构造与空字符跳过规则public class JsonReader { public init(inputStream: InputStream) }JsonReader的构造函数接收一个 InputStream 实例如ByteBuffer、StringReader等实现了该接口的输入流。文档明确说明JsonReader从输入流读取数据时会跳过非JsonString中的空字符\0、\t、\n、\r因此传入的 JSON 文本即使带有缩进换行也不会干扰 token 识别。2.2 结构游标startObject / endObject / startArray / endArray这组方法负责在 JSON 流中推进结构游标方法行为startObject(): Unit从当前位置跳过空白字符后消耗一个{字符endObject(): Unit从当前位置跳过空白字符后消耗一个}字符必须与之前的startObject配对startArray(): Unit从当前位置跳过空白字符后消耗一个[字符endArray(): Unit从当前位置跳过空白字符后消耗一个]字符必须与之前的startArray配对当输入流的 JSON 数据不符合格式时上述方法都会抛出IllegalStateException。也就是说endArray/endObject在游标位置不对时应答错误例如缺少配对的startArray/startObject时会直接报错这体现了 API 对 JSON 结构合法性的强制校验。2.3 前瞻与读取peek / readName / readValuepeek(): OptionJsonToken获取输入流下一个JsonToken的类型不消耗token也不保证下一个 token 的格式一定正确。例如输入流中下一个字符为t时peek()返回JsonToken.Bool但随后调用readValueBool()不一定成功因为t后面未必跟着完整的true。当到达输入流结尾时返回None。若下一个字符不在(n, t, f, , 0~9, -, {, }, [, ])范围内抛出IllegalStateException。readName(): String从当前位置读取一个 object 的 name键名。readValueT(): T where T : JsonDeserializableT从当前位置读取一个 value。泛型约束要求T实现了JsonDeserializableT接口这正是反序列化类型支持的统一入口。readValueString()有一个非常容易踩坑的细节文档给出了三条规则下一个 token 是JsonString时反序列化过程会按照 ECMA-404 标准对读到的 String 进行转义处理下一个 token 是JsonInt/JsonFloat/JsonBool/JsonNull其中之一时会读取下一个 value 字段的原始字符串并返回下一个 token 是其它类型时调用此接口会抛异常。这一设计使得以 String 兜底读取任意标量值成为可能例如读取{version: 2}时用readValueString()会得到2而非报错。2.4 原始字节与跳过readValueBytes / skipreadValueBytes(): ArrayByte读取下一组数据的原始字节不进行任何转义。规则为next token 是 value 时读取直到遇到,、}、]等结束符号为止的全部原始字节next token 是 Name 时读取(name value)整个组合的原始字节next token 是 BeginArray 时读取整个 Array 内的所有原始字节next token 是 BeginObject 时读取整个 Object 内的所有原始字节next token 是 EndArray / EndObject / None 时不做任何操作返回空数组且再次执行peek()仍返回原结果。skip(): Unit从当前位置跳过一组数据。规则与readValueBytes一致但跳过 value 时不检查该 value 格式是否正确因此可用于快速丢弃不需要的字段提升解析吞吐。这两个方法对只关心 JSON 中部分字段、其余原样透传的场景非常有用——例如网关转发、日志采样等可以先用skip()跳过不关心的字段或用readValueBytes()拿到原始字节后直接回写输出流。2.5 JsonToken决定处理方式的分派依据JsonToken 枚举表示 JSON 编码字符串中的结构、名称或值类型父类型为EquatableJsonToken Hashable因此可以安全地用于比较与match分派。全部取值如下取值含义建议的配套读取方式BeginArrayJSON array 开始startArray()EndArrayJSON array 结束endArray()BeginObjectJSON object 开始startObject()EndObjectJSON object 结束endObject()Nameobject 中的 name键名readName()JsonNullJSON 的 nullreadValueOptionT()JsonBoolJSON 的 boolreadValueBool()JsonNumberJSON 的 numberreadValueFloat64()等数值类型JsonStringJSON 的 stringreadValueString()典型用法是peek()返回值与JsonToken枚举做match从而在同一个fromJson实现中分派不同的读取动作见下文示例。2.6 完整反序列化示例手写 fromJson仓库示例 sample_json_reader.md 演示了完整的自定义类型反序列化流程import stdx.encoding.json.stream.* import std.io.* import std.collection.* class A : JsonDeserializableA { var key1: OptionString None var key2: Bool false var key3: Float64 0.0 var key4: String var key5: ArrayInt64 ArrayInt64() var key6: HashMapString, String HashMapString, String() public static func fromJson(r: JsonReader): A { var res A() while (let Some(v) - r.peek()) { match (v) { case BeginObject r.startObject() while (r.peek() ! EndObject) { let n r.readName() match (n) { case key1 res.key1 r.readValueOptionString() case key2 res.key2 r.readValueBool() case key3 res.key3 r.readValueFloat64() case key4 res.key4 r.readValueString() case key5 res.key5 r.readValueArrayInt64() case key6 res.key6 r.readValueHashMapString, String() case _ () } } r.endObject() break case _ throw Exception() } } return res } // toString 略 } main() { let jsonStr ##{key1: null, key2: true, key3: 123.456, key4: string, key5: [123, 456], key6: {key7: , key8: \\a}}## var bas ByteBuffer() unsafe { bas.write(jsonStr.rawData()) } var reader JsonReader(bas) var obj A.fromJson(reader) println(obj.toString()) }运行结果为None true 123.456000 string [123, 456] [(key7, ), (key8, \a)]要点拆解用多行原始字符串字面量##...##直接书写含引号、反斜杠的 JSON 文本避免手工转义关于原始字符串字面量的规则可参考 strings.md 中多行原始字符串字面量一节通过ByteBuffer承载字节数据用unsafe { bas.write(jsonStr.rawData()) }把字符串的原始字节写入缓冲区再把ByteBuffer作为InputStream传给JsonReaderByteBuffer本身实现了 IOStream 与Seekable是内存流式处理的常用载体peek()返回OptionJsonTokenwhile (let Some(v) - r.peek())是仓颉的可空绑定 while-let语法循环直到流结束None内层while (r.peek() ! EndObject)配合readName()逐个读取键名再按 name 用match分派到具体的readValueT()未知字段落入case _ ()被安全忽略null字段通过readValueOptionString()读成None体现了 Option 类型 在 JSON null 场景下的标准处理方式。三、JsonWriter链式流式序列化3.1 构造、缓存与 flush 约定public class JsonWriter { public var writeConfig WriteConfig.compact public init(out: OutputStream) }JsonWriter构造函数接收一个 OutputStream如ByteBuffer、BufferedOutputStream、文件流等。两个关键约定内部使用缓存以减少写入 Stream 时的 IO 次数因此在结束使用JsonWriter之前必须调用flush()把缓存中的数据全部写入目标流否则数据可能丢失flush()除了写出缓存还会调用目标out自身的 flush 方法所以对包装了底层缓冲的输出流如BufferedOutputStream同样生效。writeConfig是public var字段默认为WriteConfig.compact可在构造后随时修改以切换输出格式详见第四节。3.2 结构化写入startObject / endObject / startArray / endArray / writeNamestartObject(): Unit开始序列化一个新的 JSON object每个startObject都必须有对应的endObject否则抛IllegalStateExceptionendObject(): Unit结束当前 JSON object若 writer 状态不应结束 object 则抛异常startArray(): Unit/endArray(): Unit同样的配对约束适用于 JSON 数组writeName(name: String): JsonWriter在 object 结构中写入 name键名返回当前 writer 引用以便链式调用若当前状态不允许写入该 name 则抛IllegalStateException。3.3 值写入writeValue / writeNullValue / jsonValuewriteValueT(v: T): JsonWriter where T : JsonSerializable将实现了JsonSerializable的类型写入流中内部会调用泛型T的toJson方法。文档明确json.stream 已为基础类型Int64、UInt64、Float64、Bool、String以及集合类型Array、ArrayList、HashMap扩展实现了JsonSerializable因此这些类型可直接作为writeValue的实参writeNullValue(): JsonWriter向流中写入 JSON valuenulljsonValue(value: String): JsonWriter将符合 JSON value 规范的原始字符串直接写入流。此函数不会转义也不会为入参添加双引号要求调用者保证value符合 ECMA-404 标准。当value为空字符串时抛IllegalStateException。该 API 适用于性能敏感的预格式化值直写场景例如写入一段预先算好的数值表达式。所有写 value 的方法在 writer 状态不允许写入 value 时都会抛IllegalStateException例如在startObject()之后、writeName()之前直接调用writeValue。3.4 完整序列化示例自定义类型 toJson仓库示例 sample_json_writer.md 演示了自定义类型实现JsonSerializable的写法import stdx.encoding.json.stream.* import std.io.{ByteBuffer, readToEnd} class Image : JsonSerializable { var width: Int64 var height: Int64 var title: String var ids: ArrayInt64 public init() { width 0 height 0 title ids ArrayInt64() } public func toJson(w: JsonWriter): Unit { w.startObject() w.writeName(Width).writeValue(width) w.writeName(Height).writeValue(height) w.writeName(Title).writeValue(title) w.writeName(Ids).writeValueArrayInt64(ids) w.endObject() } } main() { let image Image() image.width 800 image.height 600 image.title View from 15th Floor image.ids [116, 943, 234, 38793] let stream ByteBuffer() let writer JsonWriter(stream) /* 将图片序列化 */ writer.writeValue(image) writer.flush() println(String.fromUtf8(readToEnd(stream))) }运行结果{Width:800,Height:600,Title:View from 15th Floor,Ids:[116,943,234,38793]}要点拆解writeName(...).writeValue(...)构成链式调用——这正是writeName/writeValue返回JsonWriter引用的设计目的最外层对象通过writer.writeValue(image)一次性写入其内部由Image.toJson递归地写出完整结构序列化完成后必须writer.flush()再通过readToEnd(stream)读出全部字节并用String.fromUtf8还原文本示例输出为紧凑格式默认WriteConfig.compact字段之间没有空格和换行。四、WriteConfig输出格式的精细化控制WriteConfig 是JsonWriter的序列化格式配置结构体提供两个预置常量并允许通过mut属性自定义。4.1 预置格式compact 与 prettycompact默认各属性值为属性值newline空字符串不换行indent空字符串无缩进useSpaceAfterSeparatorsfalsehtmlSafefalsedateTimeFormatDateTimeFormat.RFC3339输出示例{Name:zhangsan,Age:18,Scores:[88.8,99.9],Class:{Name:Class A,Students Number:33}}pretty各属性值为属性值newline\nindent 4 个空格useSpaceAfterSeparatorstruehtmlSafefalsedateTimeFormatDateTimeFormat.RFC3339输出示例{ Name: zhangsan, Age: 18, Scores: [ 88.8, 99.9 ], Class: { Name: Class A, Students Number: 33 } }4.2 自定义属性属性类型说明合法性约束newlineStringmut序列化时填入的换行符。非空合法值时startObject/startArray、插入元素及对应结束操作会产生换行空字符串时不换行取值须匹配正则^[\r\n]*$否则抛IllegalArgumentExceptionindentStringmut每个缩进级别填入的缩进字符串在换行生效时作为换行后的填充符取值须匹配正则^[ \t]*$仅空格和制表符否则抛IllegalArgumentExceptionuseSpaceAfterSeparatorsBoolmut在:和,后是否加一个空格为 true 时每插入一个 field name 或 array 元素后自动写入一个空格只对 object 的 field 与 array 的元素生效htmlSafeBoolmut是否转义 HTML 字符、、、、为 true 时转义为对应的 Unicode 编码字符串只对 JSON value 中的字符串字面量生效dateTimeFormatStringmut序列化DateTime类型时的格式控制功能与DateTime.toString(DateTimeFormat)一致参考 DateTimeFormat预置RFC3339 yyyy-MM-ddTHH:mm:ssOOOO使用方式见 sample_json_writeconfig.mdimport stdx.encoding.json.stream.{JsonWriter, WriteConfig, JsonSerializable} import std.io.ByteBuffer main() { /* 构造 JsonWriter */ let buffer ByteBuffer() let writer JsonWriter(buffer) /* 设置 JSON 写格式配置 */ let fmtCfg WriteConfig.pretty writer.writeConfig fmtCfg /* 写 JSON */ writer.writeValue(MyObj()) /* 打印 JSON 序列化字符串 */ println(String.fromUtf8(buffer.bytes())) } class MyObj : JsonSerializable { public func toJson(w: JsonWriter): Unit { w.startObject() w.writeName(Name).writeValue(zhangsan) w.writeName(Age).writeValue(18) w.writeName(Scores).writeValue([88.8, 99.9]) w.writeName(Class) w.startObject() w.writeName(Name).writeValue(Class A) w.writeName(Students Number).writeValue(33) w.endObject() w.endObject() w.flush() } }由于writeConfig是public var同一个JsonWriter可以在不同阶段切换格式htmlSafe属性则对嵌入 HTML 上下文如网页端 JSON 内联的输出安全很有价值。注意indent取正则^[ \t]*$、newline取正则^[\r\n]*$自定义时若传入空格/换行以外的字符会立即抛IllegalArgumentException。五、接口与内置类型支持矩阵5.1 JsonSerializable 与 JsonDeserializable序列化与反序列化是两个方向相反、签名不对称的接口public interface JsonSerializable { func toJson(w: JsonWriter): Unit } public interface JsonDeserializableT { static func fromJson(r: JsonReader): T }JsonSerializable是实例方法toJson(w)在对象内部描述如何把自身写入JsonWriterJsonDeserializableT是静态方法fromJson(r)负责从JsonReader构造一个T实例其泛型约束T : JsonDeserializableT与JsonReader.readValueT()的约束一一对应。5.2 内置扩展支持根据接口文档与包概览json.stream已为以下类型内置实现无需用户手写通过extend机制附加基础数据类型String、Int8、Int16、Int32、Int64、UInt8、UInt16、UInt32、UInt64、IntNative、UIntNative、Float16、Float32、Float64、Bool集合类型ArrayT、ArrayListT、HashMapString, T元素/值类型同样需要实现对应接口其它类型OptionT、BigInt、Decimal、DateTime。其中几个值得注意的行为数值类Int*/UInt*/Float*在反序列化时若读取的数据超出类型范围会抛OverflowExceptionDateTime的反序列化按RFC3339规范解析可包含小数秒行为参考DateTime.parse(String)解析失败抛TimeParseExceptionDateTime的序列化则受writeConfig.dateTimeFormat控制可通过修改该属性实现不同的时间格式输出String的fromJson行为与readValueString()的注意点完全一致遇到JsonString按 ECMA-404 转义遇到JsonNumber/JsonBool/JsonNull读取原始字符串其它 token 抛异常。六、工程实践建议读取端总是以peek()驱动利用while (let Some(v) - r.peek())match (v)的骨架处理流遇到未知字段用skip()跳过保证对 JSON 结构演进的兼容性写入端严格配对结构调用startObject/endObject、startArray/endArray必须成对出现配对错误会在运行时抛IllegalStateException建议把对象级序列化逻辑封装进各自的toJson方法以避免混乱不要忘记flush()JsonWriter有内部缓存结束前不 flush 会导致数据丢失flush 还会级联调用目标流的 flush因此对ByteBuffer、BufferedOutputStream等场景同样安全按需选择格式默认compact适合网络传输与日志单行记录pretty适合调试与人类可读输出自定义newline/indent/useSpaceAfterSeparators前务必确认取值满足^[\r\n]*$与^[ \t]*$正则约束善用原始字节通道对透传/转发场景使用readValueBytes()或jsonValue()可跳过转义开销前提是数据已符合 JSON 规范内存流承载ByteBuffer同时实现IOStream与Seekable是内存中流式 JSON 处理最便捷的载体从网络或文件读取时可将JsonReader/JsonWriter与标准 io 包的输入输出流组合使用实现真正的流式处理而无需全量载入内存。七、扩展阅读包总览json_stream_package_overview.md类 APIencoding_json_stream_package_classes.md接口 APIencoding_json_stream_package_interfaces.md枚举 APIencoding_json_stream_package_enums.md配置结构体encoding_json_stream_package_structs.md反序列化示例sample_json_reader.md序列化示例sample_json_writer.md格式配置示例sample_json_writeconfig.md同族树模型包encoding.json 包概览时间格式基础DateTimeFormat 类内存流载体ByteBuffer 类赞分享文档知识库教程OpenHarmony【免费下载链接】CangjieCorpus本仓库为仓颉编程语言语料库聚焦 仓颉编程语言 核心知识体系整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源经结构化处理与专业标注构建为支持 RAG检索增强生成技术 的高质量知识基座适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用推动鸿蒙开发生态智能化升级项目地址https://gitcode.com/Cangjie/CangjieCorpus点击查看免费下载相关推荐仓颉 stdx.encoding.json.stream 包实战用 JsonWriter 与 JsonReader 完成 JSON 数据流序列化与反序列化仓颉 stdx.encoding.json.stream 包实战用 JsonWriter 与 JsonReader 完成 JSON 数据流序列化与反序列化 本标准库网络密码学并发编程cangjie_stdx json.stream 包实战指南JsonReader 与 JsonWriter 的流式 JSON 序列化/反序列化全解析cangjie_stdx json.stream 包实战指南JsonReader 与 JsonWriter 的流式 JSON 序列化/反序列化全解析 stdx标准库网络密码学并发编程仓颉 stdx JsonWriter 实战用 Json Stream 把仓颉对象流式序列化为 JSON仓颉 stdx JsonWriter 实战用 Json Stream 把仓颉对象流式序列化为 JSON stdx.encoding.json.stream 是标准库网络密码学并发编程上一篇Darklang 项目安装与配置指南下一篇突破Rust嵌入困境Goscript让Go语法成为你的脚本引擎新范式创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考