直接用json.marshalindent+os.writefile是最简路径,但必须处理字段导出(首字母大写+json tag)、目录预建(os.mkdirall)和错误传播(分别检查marshal与writefile错误)三个关键点。

直接用 json.MarshalIndent + os.WriteFile 是最简可行路径,但必须处理字段导出、目录预建和错误传播这三个关键点。
结构体字段必须首字母大写且加 json tag
Go 的 json 包只序列化导出字段(即首字母大写的字段),小写字段会被静默忽略。不加 json tag 也能工作,但键名会是 Go 字段名(如 Name → "Name"),不符合常规 JSON 命名习惯。
- 推荐显式声明:
Name string `json:"name"`,控制键名大小写 - 空值处理加
omitempty:例如Email string `json:"email,omitempty"`,避免空字符串出现在输出中 - 嵌套结构体、切片、指针都支持,但
func、chan、含interface{}的 map 会触发json: unsupported type错误
写入前必须确保父目录存在
os.WriteFile 不创建上级目录,路径中任意一级不存在就会报 no such file or directory。这不是权限问题,也不是文件已打开,而是路径本身不成立。
- 用
os.MkdirAll(filepath.Dir(path), 0755)预建目录,建议放在写入前统一处理 -
filepath.Join("data", "user.json")比硬拼"data/user.json"更安全(Windows 兼容) - 权限参数(如
0644)在 Windows 上被忽略,但必须传,否则编译失败
格式化写入用 json.MarshalIndent,别用 fmt.Printf 拼接
想让 JSON 可读(带缩进、换行),必须用 json.MarshalIndent,而不是把 json.Marshal 结果再用 fmt.Fprintf 加空格——后者会破坏 JSON 语法。
- 正确方式:
data, err := json.MarshalIndent(user, "", " ")(2 空格缩进) - 错误方式:先
json.Marshal得到一行字符串,再用fmt.Fprintf(w, "%s\n", string(data))—— 这只是加了换行,没缩进,也不合法 - 如果要混合非 JSON 内容(如注释、头部说明),得手动构造字符串,但那就不是“结构体序列化”了,而是文本生成,应另选方案
错误检查不能只看 Marshal,WriteFile 失败更常见
json.Marshal 失败通常是因为含不可序列化类型;而 os.WriteFile 失败更现实:磁盘满、路径无写权限、NFS 挂载失效、父目录只读等。
- 两个错误都要检查,且分开处理:
if err != nil { /* Marshal error */ }和if err != nil { /* WriteFile error */ } - 不要合并判断:
if err := json.Marshal(...) ; err != nil || os.WriteFile(...) != nil—— 逻辑混乱,错误源无法定位 - 日志中建议带上文件路径:
log.Printf("failed to write %s: %v", path, err)
最易被跳过的其实是目录预检和 WriteFile 错误处理——很多人测试时路径刚好存在、磁盘也够用,上线后第一份数据就写失败,却只看到空文件或 panic,根本没意识到是路径或权限问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











