json.Marshal不能直接处理原始文本文件,必须先解析为Go值(如struct或map)再序列化;常见错误是误将YAML格式文本直接Marshal导致输出字符串而非对象,正确做法是用正则提取字段、构造结构体或map切片,再调用json.MarshalIndent生成可读JSON。

json.Marshal 不能直接处理原始文本文件 —— 它只接受 Go 值(如 struct、map、slice),不认 YAML 风格或自定义格式的纯文本。你得先解析,再序列化。
用正则提取字段再构造结构体
常见错误是直接对 test.txt 内容调用 json.Marshal,结果得到一串字符串的 JSON(比如 "{\n- name: server1\n type: food\n}"),而不是真正的对象数组。
实际做法是:
- 读取文件内容为
string - 用
regexp.MustCompile匹配每段(例如)- name: ([^\n]+)\n type: ([^\n]+) - 每次匹配后新建一个结构体实例,append 到 slice
- 最后用
json.Marshal序列化整个 slice
re := regexp.MustCompile(`- name: ([^\n]+)\n type: ([^\n]+)`)
matches := re.FindAllStringSubmatchIndex([]byte(str), -1)
var items []struct{ Name, Type string }
for _, m := range matches {
name := strings.TrimSpace(string(str[m[0][0]+8 : m[0][1]]))
typ := strings.TrimSpace(string(str[m[1][0]+8 : m[1][1]]))
items = append(items, struct{ Name, Type string }{name, typ})
}
data, _ := json.Marshal(items)
注意:正则要小心换行和空格;FindAllStringSubmatchIndex 比 FindAllStringSubmatch 更可控,避免越界 panic。
不用结构体,用 map[string]interface{} 动态组装
如果你不想定义结构体(比如字段名/数量不固定),可以用 map[string]interface{}:
- 每次匹配出 key-value 对后,构造一个
map[string]interface{} - append 到
[]map[string]interface{} - 直接传给
json.Marshal
var items []map[string]interface{}
for _, m := range matches {
item := map[string]interface{}{
"name": strings.TrimSpace(...),
"type": strings.TrimSpace(...),
}
items = append(items, item)
}
jsonBytes, _ := json.Marshal(items)
这种写法灵活,但失去编译期类型检查;如果字段名拼错(比如写成 "Name" 而不是 "name"),运行时才暴露。
避免 json.Marshal 输出无缩进的“一行 JSON”
json.Marshal 默认输出紧凑格式(无换行、无缩进),不利于调试或人工阅读。
改用 json.MarshalIndent:
- 第二个参数是前缀(通常为空字符串)
- 第三个参数是缩进符(常用
" "或"\t")
jsonBytes, _ := json.MarshalIndent(items, "", " ")
注意:缩进会增大字节数,生产环境 API 响应一般不用;仅开发期或日志输出时开启。
文件读取失败或编码问题导致 marshal 后为空或 panic
常见现象:json.Marshal 返回空字节切片或 panic,但没报错。
原因通常是:
-
ioutil.ReadFile(Go 1.16+ 推荐用os.ReadFile)返回 error 被忽略,str是空字符串 - 文件含 UTF-8 BOM 或非 UTF-8 编码(如 GBK),
string(b)解析异常,正则匹配失败,最终items为空 slice - 正则未覆盖所有行(比如末尾缺换行),
FindAllXXX漏掉最后一组
建议:
- 检查
err并提前 return - 用
strings.TrimSpace清理每行前后空白 - 打印
len(matches)和前几条item确认是否真解析到了
最易被忽略的是:正则表达式里的换行符在 Windows 上是 \r\n,而你的模式只写了 \n —— 这会导致匹配失败,且毫无提示。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











