Golang中如何将JSON对象保存到平面文件
Golang中如何将JSON对象保存到平面文件 我有一个需求,需要将JSON保存下来,并在解组后修改结构体的字段,然后写回到同一个文件中。
假设我有以下结构体
type struct1 struct{
St1B bool
St1I int
}
type struct2 struct{
St2S string
St2B bool
}
我初始化这些值
pp := &struct1{
St1B : true,
St1I : 23,
}
dd := &struct2{
St2S : "Hello",
St2B : false,
}
将它们插入到如下所示的映射中后
Configs = make(map[string]interface{})
Configs["st1"] = pp
Configs["st2"] = dd
我应该如何将其写入JSON文件并读取它,以便它能正确解组到相应的结构体?
我尝试了以下方法,但它只会处理"pp"结构体,而不会处理其他结构体如"dd"或其他可能存在的结构体。
jdata1, err := json.MarshalIndent(pp, "", " ")
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(jdata1))
jsonFile, err := os.Create("./data.json")
jsonFile.Write(jdata1)
基本上,我试图将这些结构体的值保存到一个平面文件中,并能在修改之前检索它。 任何建议都将不胜感激。
更多关于Golang中如何将JSON对象保存到平面文件的实战教程也可以访问 https://www.itying.com/category-94-b0.html
为便于记录,我已将您的代码放入Go Playground以便重现问题:https://play.golang.com/p/fGDUckeIPvf
更多关于Golang中如何将JSON对象保存到平面文件的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
只有通过实际操作才能更好地理解这些内容。感谢您帮助我理解。
mholt 的这个工具可以让你查看 JSON 对象如何映射到 Go 结构体类型。https://mholt.github.io/json-to-go/
这很容易做到:https://play.golang.com/p/kZyiphK6ve6
请查看encoding/json包的文档,其中解释了所有这些内容。
感谢 Iutzhorn,这个实现起来相当简单。作为这方面的新手,我现在打算尝试从 JSON 文件中读取数据并将其反序列化到两个不同的结构体中。如果能就如何实现这一点提供建议,那将非常有帮助。
仅序列化 Configs,而不仅仅是 pp:
jdata1, err := json.MarshalIndent(Configs, "", " ")
结果:
{
"st1": {
"St1B": true,
"St1I": 23
},
"st2": {
"St2S": "Hello",
"St2B": false
}
}
好的,我可能理解有误,但我想实现的是:https://play.golang.com/p/g3clTg9pfiA
configs2 := struct2{}
err2 := json.Unmarshal([]byte(jsonBlob2), &configs2)
期望 configs2 能够被填充为 “struct2” 解组后的值。
目前实际结果是:
%q { false}
这是 struct2 内部布尔类型的默认值。
为什么它不能直接解组到结构体中呢?
因为你尝试将这个JSON
{
"st2": {
"St2S": "Hello",
"St2B": true
}
}
反序列化到这个结构体:
type struct2 struct {
St2S string
St2B bool
}
你需要一个内部导出的struct2成员来接收st2:
package main
import (
"encoding/json"
"fmt"
)
type struct2 struct {
St2 struct2inner
}
type struct2inner struct {
St2S string
St2B bool
}
func main() {
jsonBlob2 := `{
"st2": {
"St2S": "Hello",
"St2B": true
}
}`
configs2 := struct2{}
err2 := json.Unmarshal([]byte(jsonBlob2), &configs2)
if err2 != nil {
fmt.Println("error:", err2)
}
fmt.Println("%q", configs2)
}
运行结果:
%q {{Hello true}}
要将包含不同类型结构体的映射保存为JSON文件并正确解组,可以使用以下方法:
package main
import (
"encoding/json"
"fmt"
"os"
)
type struct1 struct {
St1B bool
St1I int
}
type struct2 struct {
St2S string
St2B bool
}
var Configs map[string]interface{}
func saveToFile(filename string) error {
// 将整个Configs映射序列化为JSON
data, err := json.MarshalIndent(Configs, "", " ")
if err != nil {
return err
}
// 写入文件
return os.WriteFile(filename, data, 0644)
}
func loadFromFile(filename string) error {
// 读取文件内容
data, err := os.ReadFile(filename)
if err != nil {
return err
}
// 临时存储解组后的数据
tempConfigs := make(map[string]json.RawMessage)
// 第一层解组到RawMessage
if err := json.Unmarshal(data, &tempConfigs); err != nil {
return err
}
// 重新初始化Configs
Configs = make(map[string]interface{})
// 根据键名分别解组到对应的结构体
for key, raw := range tempConfigs {
switch key {
case "st1":
var st1 struct1
if err := json.Unmarshal(raw, &st1); err != nil {
return err
}
Configs[key] = &st1
case "st2":
var st2 struct2
if err := json.Unmarshal(raw, &st2); err != nil {
return err
}
Configs[key] = &st2
default:
// 对于未知类型,保持原始JSON数据
var unknown interface{}
if err := json.Unmarshal(raw, &unknown); err != nil {
return err
}
Configs[key] = unknown
}
}
return nil
}
func main() {
// 初始化数据
pp := &struct1{
St1B: true,
St1I: 23,
}
dd := &struct2{
St2S: "Hello",
St2B: false,
}
Configs = make(map[string]interface{})
Configs["st1"] = pp
Configs["st2"] = dd
// 保存到文件
if err := saveToFile("config.json"); err != nil {
fmt.Println("保存错误:", err)
return
}
// 修改前读取文件
if err := loadFromFile("config.json"); err != nil {
fmt.Println("读取错误:", err)
return
}
// 验证读取的数据
if st1, ok := Configs["st1"].(*struct1); ok {
fmt.Printf("读取的st1: St1B=%v, St1I=%d\n", st1.St1B, st1.St1I)
}
if st2, ok := Configs["st2"].(*struct2); ok {
fmt.Printf("读取的st2: St2S=%s, St2B=%v\n", st2.St2S, st2.St2B)
}
// 修改数据示例
if st1, ok := Configs["st1"].(*struct1); ok {
st1.St1I = 100
st1.St1B = false
}
if st2, ok := Configs["st2"].(*struct2); ok {
st2.St2S = "Modified"
st2.St2B = true
}
// 保存修改后的数据
if err := saveToFile("config.json"); err != nil {
fmt.Println("保存修改错误:", err)
return
}
}
生成的JSON文件内容:
{
"st1": {
"St1B": true,
"St1I": 23
},
"st2": {
"St2S": "Hello",
"St2B": false
}
}
这种方法的关键点:
- 使用
json.RawMessage进行两阶段解组,先获取原始JSON数据,再根据键名分配到具体结构体 - 在
loadFromFile函数中通过switch语句根据键名选择对应的结构体类型 - 保存时直接序列化整个Configs映射
- 读取时能正确恢复原始结构体类型,支持后续修改操作
这样就能实现将包含不同类型结构体的映射保存到文件,并在需要时正确读取和修改。

