最稳妥方式是先用 json.marshal 序列化结构体为字节切片,再用 os.writefile 写入文件;需确保字段导出、添加 json tag、严格检查每一步 Error。

用 json.Marshal 序列化结构体再写入文件最稳妥
go 标准库不提供直接“一键保存 JSON 到文件”的函数,必须分两步:先序列化为字节切片,再写入文件。跳过 json.Marshal 直接用 json.Encoder 虽可行,但出错时难定位是数据问题还是 IO 问题。
常见错误:结构体字段没加导出(首字母小写),导致序列化后是空对象 {};或忘记处理 json.Marshal 返回的 error,结果写入了 nil 字节流。
- 确保结构体字段首字母大写,且加上
jsontag(如Username String `json:"username"`) - 始终检查
json.Marshal的 error,不要忽略 - 写文件建议用
os.WriteFile(Go 1.16+),简洁且自动处理 close
data := struct{ Name string `json:"name"` }{Name: "Alice"} b, err := json.Marshal(data) if err != nil { log.Fatal(err) } err = os.WriteFile("user.json", b, 0644) if err != nil { log.Fatal(err) }
用 json.Encoder 流式写入适合大数据或嵌套结构
当你要写入大量 JSON(比如数组元素逐个生成)、或结构体嵌套很深、或需控制缩进/换行时,json.Encoder 更灵活。它直接写入 io.Writer,可接文件、网络连接甚至内存 buffer。
容易踩的坑:忘记调用 encoder.Encode()(不是 EncodeAll),或误以为一次 Encode 能写多个值——它每次只写一个 JSON 值,多次调用会生成多个独立 JSON 对象(非合法 JSON 数组)。
立即学习“go语言免费学习笔记(深入)”;
- 写入数组需手动输出
[和],并在元素间加逗号 - 用
encoder.SetIndent("", " ")可美化输出(但有性能开销) - 如果写入失败,error 发生在
Encode()调用时,不是Close()时
f, _ := os.Create("users.json") defer f.Close() enc := json.NewEncoder(f) enc.SetIndent("", " ") enc.Encode(map[string]string{"id": "1", "role": "admin"}) enc.Encode(map[string]string{"id": "2", "role": "user"}) // 注意:这会生成两行独立 JSON,不是 { ... } 包裹的数组
读取 JSON 文件务必检查 json.Unmarshal 的 error
很多人只检查 os.Open 错误,却忽略 json.Unmarshal 失败——比如文件内容是 {name: "bob"}(key 缺少引号),或类型不匹配(JSON 中是字符串,Go 结构体字段却是 int)。
典型现象:程序不报错,但结构体字段全是零值(""、0、nil),调试时才发现是 unmarshal 失败被静默吞掉了。
- 永远用
err != nil判断json.Unmarshal是否成功 - 若 JSON 字段可能缺失或类型不确定,用
map[string]Interface{}或自定义UnmarshalJSON方法 - 避免用
json.RawMessage过度延迟解析,除非真需要跳过某段结构校验
注意文件权限与路径,windows 和 linux 行为一致但路径分隔符要小心
os.WriteFile 和 os.Open 在 Windows 和 Linux 下对路径分隔符都支持 /(Go 运行时自动转换),但硬编码 会导致编译失败或路径错误。另外,文件权限参数(如 0644)在 Windows 上被忽略,但在 Linux/macos 上决定能否读写。
- 路径拼接统一用
path/filepath.Join,别用字符串 + - 写入前确保目录存在,
os.WriteFile不会自动创建父目录,要用os.MkdirAll - 临时测试时避免写到根目录或系统路径,优先用相对路径如
./data/config.json
最常被忽略的是:JSON 写入后没刷新缓冲区(其实 os.WriteFile 和 json.Encoder 的 Close 都已处理),但如果你用 bufio.Writer 包装文件,就一定得记得 Flush() ——否则内容可能卡在内存里没落盘。