直接用 json.encoder 而不是 json.marshal 是因为前者内存占用为常数级,适合大数据流式编码;后者会将整个结构体序列化为 []byte,内存随数据量线性增长。

为什么直接用 json.Encoder 而不是 json.Marshal
当你处理大量数据(比如数据库扫描结果、日志流、HTTP 响应体)时,json.Marshal 会把整个结构体序列化成一个 []byte 再写入,内存占用随数据量线性增长;而 json.Encoder 直接向 io.Writer(如 http.ResponseWriter、os.Stdout、bufio.Writer)逐块写入,常数级内存开销。它不缓存完整 JSON,只维护编码状态。
典型适用场景:HTTP 接口返回大数组、导出 CSV 转 JSON 流、实时日志 JSON 化推送。
json.Encoder 必须显式调用 Encode(),不能靠 defer 或自动 flush
json.Encoder 没有内置缓冲区自动刷出机制,每次写入都依赖你主动调用 Encode()。漏掉这一步,什么都不会输出——连空对象也不会生成。
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 错误写法:
enc := json.NewEncoder(w); enc.Encode(v) // ✅ 正确,但如果你只写了json.NewEncoder(w)就结束函数,输出为空 - 写多个值时,每个都要单独
Encode(),它会在每个值后自动加换行(非格式化模式下),但不会自动加逗号或方括号——也就是说,它不帮你构造 JSON 数组,只是连续编码多个独立 JSON 值(即 JSON Text Sequences,RFC 7464) - 如果目标是标准 JSON 数组
[{...},{...}],得手动写[、逗号分隔、],或者改用切片一次性编码
如何正确写出合法 JSON 数组流(带逗号和括号)
默认 json.Encoder 对每个 Encode() 调用输出一个完整 JSON 值,彼此无关联。要得到 [{},{},{}],有两条路:
- 简单数据量可控:先收集进
[]interface{}或结构体切片,再用json.Marshal或enc.Encode(slice)一次性输出——这是最常见且安全的做法 - 真正流式、数据不可全量加载:手动控制结构
w.Write([]byte{'['}) first := true for _, v := range stream { if !first { w.Write([]byte{','}) } first = false enc.Encode(v) // 注意:这里会自带换行,如需紧凑格式,用 bufio.NewWriter + enc.SetIndent("", "") } w.Write([]byte{']'}) - 注意:手动写
[和]后,别忘了检查enc.Encode()是否返回 error,否则可能 JSON 半截就断了
编码器配置影响输出行为,但不改变流式本质
json.Encoder 提供 SetIndent(prefix, indent string) 控制缩进,但它只是在每个字段/元素前插入指定字符串,并不改变“逐次写入”的逻辑;也支持 SetEscapeHTML(bool) 防止 被转义为 <code>\u003c(API 返回 HTML 片段时有用)。
- 性能提示:开启
SetIndent会显著降低吞吐量,生产 API 建议关闭(保持默认空字符串) - 并发安全:
*json.Encoder不是并发安全的,多个 goroutine 同时调用Encode()会破坏输出——必须加锁或为每个 goroutine 分配独立 encoder - 错误处理:每次
Encode()都应检查 error,尤其写入网络或文件时,底层io.Writer可能中途断开










