utf8jsonwriter 适合高性能、低内存占用的 json 生成场景,如 api 流式响应、结构化日志和大数据导出;它直接写入 utf-8 字节,无反射、无中间对象,比 jsonserializer 快 2–5 倍且 gc 压力极低。

Utf8JsonWriter 适合什么场景
需要高性能、低内存占用地生成 JSON 字符串(比如 API 响应流式输出、日志结构化、大数据量导出),且不依赖对象序列化逻辑——Utf8JsonWriter 是纯写入器,不反射、不缓存、不构建中间对象树。
它直接向 Stream 或 Span<byte></byte> 写入 UTF-8 字节,跳过字符串编码/解码开销。如果你只是拼个 JSON 片段或配合 HttpResponse.Body 边写边发,它比 JsonSerializer.Serialize 快 2–5 倍,GC 压力极低。
初始化时必须注意缓冲区和编码
Utf8JsonWriter 默认使用 Stream 构造函数,但若传入未设置 CanWrite == true 的流(如只读的 MemoryStream 视图)、或未预分配足够容量的 MemoryStream,会在写入中途抛 IOException 或触发频繁扩容。
- 写入到响应体:直接传
context.Response.Body,确保响应头已设"Content-Type: application/json; charset=utf-8" - 写入到内存:用
new MemoryStream(4096)预分配缓冲,避免小块多次分配;完成后调用stream.Position = 0再读取 - 绝对不要传
Encoding.UTF8.GetBytes("...")得到的字节数组封装成ReadOnlyMemory<byte></byte>——Utf8JsonWriter只接受可写的IBufferWriter<byte></byte>或Stream
写入嵌套结构必须严格配对 Begin/End 方法
没有自动补全,漏掉一个 WriteEndArray() 就会产出非法 JSON,且运行时不报错,只在下游解析时报 JsonReaderException: Unexpected end of input。
常见错误模式:
- 循环中写对象但忘了在循环外
WriteStartArray()和WriteEndArray() - 条件分支里写了
WriteStartObject(),但某些分支没写对应WriteEndObject() - 调用
WritePropertyName("items")后,误用WriteString("value")而不是WriteStartArray()+ 子项 +WriteEndArray()
示例(正确嵌套):
writer.WriteStartObject();
writer.WriteString("name", "Alice");
writer.WriteStartArray("hobbies");
writer.WriteString("reading");
writer.WriteString("coding");
writer.WriteEndArray(); // ← 必须有
writer.WriteEndObject(); // ← 必须有
字符串和数值写入要选对重载方法
WriteString(string) 和 WriteString(ReadOnlySpan<char>)</char> 性能差一倍以上;后者避免字符串分配,但需确保 span 生命周期覆盖写入过程。数值同理:WriteNumber(int) 比 WriteString(int.ToString()) 快且安全(无文化相关格式风险)。
- 字段名永远用
WritePropertyName(string),不要用WriteString()模拟 - 写原始 JSON 片段(如已有合法 JSON 字符串)用
WriteRawValue(string, skipInputValidation: true),但必须确保内容本身是合法 UTF-8 JSON - 写
null用WriteNull(),别写WriteString("null") - 时间类型建议转为 ISO 8601 字符串后用
WriteString(),Utf8JsonWriter不内置日期格式化
Flush()(尤其写入 Stream 时),否则最后几个字节可能卡在缓冲区里发不出去。另外,它不处理换行缩进——需要美化输出就得自己加 JsonWriterOptions 并设 Indented = true,但这会明显降低性能。










