正确读取JSON文件需先用os.ReadFile加载字节再json.Unmarshal,注意错误处理、BOM处理、结构体字段导出与json tag、空值类型匹配、大文件流式解析及编码转换。
json.Unmarshal 读取文件内容会 panic,必须先读文件再解码很多人写成这样:
data := []byte("config.json")
json.Unmarshal(data, &cfg)——这其实只是把字符串字面量当 JSON 解析了,根本没读文件。正确流程是两步:先用 os.ReadFile(Go 1.16+)或 ioutil.ReadFile(旧版)加载文件字节,再传给 json.Unmarshal。
os.ReadFile 返回 []byte 和 error,必须检查错误,空文件或权限不足都会导致失败json.Unmarshal 要求输入是合法 UTF-8 编码的完整 JSON 文本
json.Unmarshal 会报 invalid character 'ï' looking for beginning of value,需提前 stripjson: tag 才能被解码Go 的 json 包只能设置导出字段(首字母大写),且默认按字段名匹配。如果 JSON 键名是 user_name,而结构体字段叫 UserName,不加 tag 就无法映射。
json:"user_name" 显式指定键名,支持别名、忽略字段(json:"-")、omitempty(空值不序列化)json.RawMessage 类型的兜底字段interface{} 不够用,优先用具体类型或自定义 UnmarshalJSON
遇到 JSON 数组如 "tags": ["go", "json"],用 []string 直接接收最安全;但如果 API 返回有时是字符串、有时是数组(常见于弱类型后端),硬转会 panic。
map[string]interface{} 或 []interface{},类型丢失后后续逻辑难维护、易出错UnmarshalJSON([]byte) error 方法,内部判断 json.Unmarshal 失败后尝试其他解析路径null)对应指针或 sql.NullString 等可空类型;普通值类型(如 int)遇到 null 会解码失败json.Unmarshal,改用 json.Decoder 流式解析用 os.ReadFile 把几百 MB 的 JSON 一次性读进内存,不仅慢,还可能 OOM。这时应打开文件句柄,用 json.NewDecoder 边读边解。
json.NewDecoder(f).Decode(&v) 每次只解一个顶层 JSON 值(对象或数组),适合日志行、NDJSON 格式decoder.Token() 手动跳过不需要的字段,减少内存占用
json 包只支持 UTF-8,若文件是 UTF-16,需先用 golang.org/x/text/encoding 转换os.ReadFile 是否成功,而是要区分「文件不存在」、「权限拒绝」、「JSON 语法错误」、「字段类型不匹配」这四类问题,它们对应的修复方式完全不同。