最简写入方式是json.Marshal+os.WriteFile,适合小到中等JSON数据;需确保字段导出、检查error、用MarshalIndent提升可读性,避免fmt.Fprint误写非JSON字符串。

用 json.Marshal + os.WriteFile 最简写入
直接序列化后一次性写入文件,适合小到中等体积的 JSON 数据(比如配置、状态快照)。json.Marshal 返回 []byte,配合 os.WriteFile 两步到位,代码干净且不易出错。
常见错误是忽略返回的 error,导致写入失败却无感知;还有人误用 fmt.Fprint 直接写 interface{},结果存的是 {main.MyStruct{...}} 这种字符串,不是合法 JSON。
-
json.Marshal不会自动格式化(无换行缩进),输出是紧凑 JSON;如需可读性,改用json.MarshalIndent -
os.WriteFile默认以0644权限创建文件,若需限制访问(如含敏感字段),显式传入0600 - 结构体字段必须是导出字段(首字母大写),否则
json.Marshal忽略它们
用 json.Encoder 流式写入大 JSON
当数据量大(例如导出上万条记录)、或需边生成边写入(避免内存堆积)时,json.Encoder 是更稳妥的选择。它把编码和写入耦合在一起,支持任意 io.Writer(包括文件、网络连接、管道)。
典型坑是忘记调用 encoder.Encode() 而只调用 encoder.Encode(nil) 或漏掉末尾换行——JSON 数组/对象本身不依赖换行,但某些解析器对末尾缺失换行敏感;另外,多次 Encode 写入同一文件,不会自动加逗号或括号,得自己拼结构。
立即学习“go语言免费学习笔记(深入)”;
- 写数组时,需手动先写
[,每项后加,,最后写];json.Encoder不负责容器语法 - 若写入目标是普通文件,用
os.Create后传给json.NewEncoder,别用os.OpenFile(..., os.O_APPEND)——追加模式下无法重置 JSON 根对象 - 编码过程中发生错误(如含不可序列化类型),
Encode立即返回 error,且后续调用会持续失败,需重建Encoder
处理 time.Time 和自定义类型时的序列化陷阱
Go 默认把 time.Time 编成带纳秒精度的 RFC3339 字符串(如 "2024-05-22T14:30:00.123456789Z"),但很多前端或旧系统只认秒级或 Unix 时间戳。直接写入会导致解析失败。
自定义类型(如 type UserID int64)默认按底层类型编码,可能丢失语义;若实现了 json.Marshaler 接口,则走自定义逻辑,但容易忘了同时实现 UnmarshalJSON 导致反序列化不一致。
- 统一控制时间格式:在结构体字段加 tag,例如
CreatedAt time.Time `json:"created_at" time_format:"2006-01-02T15:04:05Z"`,再配合同步的MarshalJSON方法 - 避免在
MarshalJSON中调用json.Marshal自身字段(引发无限递归),应转为底层类型再编码 - 写入前用
json.Valid检查字节切片是否为合法 JSON,尤其在拼接或模板注入后
文件路径与编码兼容性必须手动确认
Go 的 json 包只处理 UTF-8 编码的 JSON,不支持 GBK、UTF-16 等。如果目标系统强制要求非 UTF-8,必须在写入前转换字节流(用 golang.org/x/text/encoding),而不是指望 json 包自动适配。
路径中的中文或特殊字符在 Windows 下容易因编码或权限报错;os.WriteFile 对父目录不存在完全静默失败(只返回 no such file or directory),但其实错在目录没建好。
- 写入前用
os.MkdirAll(filepath.Dir(filename), 0755)确保路径存在 - Windows 上避免使用
:、<、>等非法文件名字符,filepath.Clean不会帮你过滤 - 若文件需被其他语言(如 Python
json.load)读取,确保不写 BOM;Go 默认不加 BOM,但若中间经过其他工具转码可能引入


















