gob.Encode只存部分字段是因为仅序列化首字母大写的导出字段,小写字段如id int被静默忽略,反序列化后为零值且不报错;必须全部改为大写开头,嵌套结构体和复合类型元素也需满足该规则。

gob.Encode 为什么只存了部分字段?
因为 gob 只序列化导出字段(首字母大写),小写字段如 id int 会被完全忽略,反序列化后仍是零值,且不报错。这是最隐蔽的坑:文件看似写成功,读出来却是空结构。
必须确保所有待持久化的字段名以大写字母开头,例如:ID int、Name string。嵌套结构体、map、slice 中的元素类型也需满足同样规则。
- 不可导出字段(
id、data map[string]interface{})→ 静默丢弃 - 导出字段含未导出内嵌结构体 → 内嵌部分字段仍被丢弃
- 字段类型含
func、channel、unsafe.Pointer→Encodepanic
写入 .gob.gz 文件时为什么解压失败?
常见原因是没调用 gzip.Writer.Close(),导致压缩流尾部(CRC、ISIZE)缺失,解压时抛出 invalid header 或 unexpected end of file。
正确顺序是:打开文件 → 创建 gzip.NewWriter → 创建 gob.NewEncoder → Encode → 显式 Close() 所有封装层。
立即学习“go语言免费学习笔记(深入)”;
- 错误写法:
defer gz.Close()放在enc.Encode()后面但没保证执行时机(比如提前 return) - 错误写法:先
gob.Encode到[]byte,再压缩 → 大对象易 OOM - 正确写法:让
gob.Encoder直接写入gzip.Writer,实现边编码边压缩
读取 .gob.gz 文件时 Decode 总是失败或 panic
根本原因是解码链路断层:gob 必须从 gzip 解压后的原始字节流读取,不能直接读压缩文件或裸 os.File。
典型错误包括:gob.NewDecoder(file)(传入的是 gzip 二进制头)、gzip.NewReader(file) 后没检查 error 就继续用、dec.Decode(user) 没传指针。
- 必须用
gzip.NewReader(file)包一层,且检查返回的err -
gob.NewDecoder的输入必须是该gzip.Reader -
Decode参数必须是&user,不是user - 如果文件里连续写了多个值(如心跳日志流),要循环调用
Decode,不能只调一次
JSON 和 gob 到底该选哪个?
选 json 当你需要人可读、跨语言、长期存档或前端交互;选 gob 当你只在 Go 进程间传递、需要保留指针关系/私有字段/类型信息,且对性能和体积敏感。
二者不可混用:用 gob 存的文件,json.Unmarshal 会 panic;反之亦然。跨版本读取时,gob 依赖 struct 字段名与顺序严格一致,改注释、调换字段顺序都可能导致静默错乱。
- JSON 适合配置、API 缓存、日志快照(加
json.MarshalIndent方便调试) - gob 适合运行时状态、爬虫中间数据、session 快照(但两端 struct 定义必须完全相同)
- 大结构体流式写入优先用
json.Encoder或gob.Encoder,别用Marshal+WriteFile全量加载


















