19 - 编码:JSON、XML、Base64、Gob、Protocol Buffers
19 - 编码
19.1 JSON
序列化
package main
import (
"encoding/json"
"fmt"
"time"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"-"` // 忽略
Age int `json:"age,omitempty"` // 零值忽略
Tags []string `json:"tags"`
CreatedAt time.Time `json:"created_at"`
Address *Address `json:"address,omitempty"` // 指针,nil 时忽略
}
type Address struct {
City string `json:"city"`
Country string `json:"country"`
}
func main() {
user := User{
ID: 1,
Name: "Alice",
Email: "[email protected]",
Password: "secret",
Age: 30,
Tags: []string{"admin", "user"},
CreatedAt: time.Now(),
Address: &Address{City: "Beijing", Country: "China"},
}
// 序列化
data, err := json.Marshal(user)
if err != nil {
panic(err)
}
fmt.Println(string(data))
// 美化输出
data2, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(data2))
}
反序列化
func main() {
jsonStr := `{
"id": 1,
"name": "Alice",
"email": "[email protected]",
"age": 30,
"tags": ["admin", "user"],
"address": {
"city": "Beijing",
"country": "China"
}
}`
var user User
err := json.Unmarshal([]byte(jsonStr), &user)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", user)
}
JSON 流式处理
// 解码器(适合大文件或流式数据)
func decodeUsers(r io.Reader) ([]User, error) {
var users []User
decoder := json.NewDecoder(r)
// 跳过数组开始
decoder.Token() // [
for decoder.More() {
var user User
if err := decoder.Decode(&user); err != nil {
return nil, err
}
users = append(users, user)
}
return users, nil
}
// 编码器
func encodeUsers(w io.Writer, users []User) error {
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
return encoder.Encode(users)
}
处理未知结构
func main() {
jsonStr := `{"name": "Alice", "age": 30, "scores": [95, 87, 92]}`
// 使用 map[string]any
var data map[string]any
json.Unmarshal([]byte(jsonStr), &data)
fmt.Println(data["name"]) // Alice
fmt.Println(data["age"]) // 30(float64 类型!)
// 使用 any
var v any
json.Unmarshal([]byte(jsonStr), &v)
// 使用 json.RawMessage 延迟解析
type Message struct {
Type string `json:"type"`
Payload json.RawMessage `json:"payload"`
}
msg := Message{}
json.Unmarshal([]byte(`{"type": "user", "payload": {"name": "Alice"}}`), &msg)
switch msg.Type {
case "user":
var user User
json.Unmarshal(msg.Payload, &user)
fmt.Println(user.Name)
}
}
19.2 XML
import "encoding/xml"
type Person struct {
XMLName xml.Name `xml:"person"`
ID int `xml:"id,attr"`
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"`
Age int `xml:"age"`
Comments []string `xml:"comments>comment"`
}
func main() {
// 序列化
p := Person{
ID: 1,
FirstName: "Alice",
LastName: "Wang",
Age: 30,
Comments: []string{"Great!", "Awesome"},
}
data, _ := xml.MarshalIndent(p, "", " ")
fmt.Println(string(data))
// 反序列化
xmlStr := `<person id="1"><name><first>Alice</first><last>Wang</last></name><age>30</age></person>`
var p2 Person
xml.Unmarshal([]byte(xmlStr), &p2)
fmt.Printf("%+v\n", p2)
}
19.3 Base64
import "encoding/base64"
func main() {
data := []byte("Hello, 世界!")
// 标准 Base64
encoded := base64.StdEncoding.EncodeToString(data)
fmt.Println(encoded)
decoded, _ := base64.StdEncoding.DecodeString(encoded)
fmt.Println(string(decoded))
// URL 安全 Base64
urlEncoded := base64.URLEncoding.EncodeToString(data)
fmt.Println(urlEncoded)
// Raw(无填充)
raw := base64.RawStdEncoding.EncodeToString(data)
fmt.Println(raw)
// 用于图片
imgData, _ := os.ReadFile("logo.png")
base64Img := base64.StdEncoding.EncodeToString(imgData)
dataURI := "data:image/png;base64," + base64Img
_ = dataURI
}
19.4 Gob
Go 专用的二进制编码格式,适合 Go 程序之间的通信。
import (
"bytes"
"encoding/gob"
"fmt"
)
type User struct {
Name string
Age int
Email string
}
func main() {
// 注册类型(用于接口类型的编码)
gob.Register(User{})
// 编码
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf)
user := User{Name: "Alice", Age: 30, Email: "[email protected]"}
if err := encoder.Encode(user); err != nil {
panic(err)
}
fmt.Printf("编码后 %d 字节\n", buf.Len())
// 解码
decoder := gob.NewDecoder(&buf)
var decoded User
if err := decoder.Decode(&decoded); err != nil {
panic(err)
}
fmt.Printf("解码: %+v\n", decoded)
// 编码多个值
var buf2 bytes.Buffer
enc := gob.NewEncoder(&buf2)
enc.Encode(42)
enc.Encode("hello")
enc.Encode([]int{1, 2, 3})
dec := gob.NewDecoder(&buf2)
var n int
var s string
var nums []int
dec.Decode(&n)
dec.Decode(&s)
dec.Decode(&nums)
fmt.Println(n, s, nums) // 42 hello [1 2 3]
}
19.5 Protocol Buffers
// user.proto
syntax = "proto3";
package demo;
option go_package = "./pb";
message User {
int32 id = 1;
string name = 2;
string email = 3;
repeated string tags = 4;
}
service UserService {
rpc GetUser(GetUserRequest) returns (User);
}
message GetUserRequest {
int32 id = 1;
}
# 生成代码
protoc --go_out=. --go-grpc_out=. user.proto
import (
"google.golang.org/protobuf/proto"
pb "myproject/pb"
)
func main() {
// 创建消息
user := &pb.User{
Id: 1,
Name: "Alice",
Email: "[email protected]",
Tags: []string{"admin", "user"},
}
// 序列化
data, err := proto.Marshal(user)
if err != nil {
panic(err)
}
fmt.Printf("Protobuf: %d bytes\n", len(data))
// 反序列化
user2 := &pb.User{}
if err := proto.Unmarshal(data, user2); err != nil {
panic(err)
}
fmt.Printf("User: %+v\n", user2)
}
格式对比
| 格式 | 可读性 | 体积 | 速度 | 跨语言 |
|---|---|---|---|---|
| JSON | ✅ 高 | 大 | 慢 | ✅ |
| XML | ✅ 高 | 最大 | 最慢 | ✅ |
| Gob | ❌ 二进制 | 中 | 快 | ❌ Go 专用 |
| Protobuf | ❌ 二进制 | 小 | 快 | ✅ |
| MessagePack | ❌ 二进制 | 小 | 快 | ✅ |
🏢 业务场景
- API 开发:JSON 序列化 HTTP 响应
- 配置文件:JSON/XML/YAML 配置解析
- gRPC 服务:Protocol Buffers 定义接口
- 缓存存储:Gob 编码对象存储到 Redis
- 文件传输:Base64 编码二进制数据