encoding - 数据编解码
概述
encoding 包及其子包提供了各种数据格式的编码和解码功能。
encoding 是什么:
- 📦 编解码标准库:Go 标准库提供的统一编解码接口
- 🔧 多种格式支持:文本、二进制、JSON、XML、CSV 等
- 📋 统一接口:定义了通用的编解码器接口
- 🛠️ 广泛应用:网络通信、数据存储、配置处理等
主要子包:
encoding/base32- Base32 编解码encoding/base64- Base64 编解码encoding/binary- 二进制编解码encoding/csv- CSV 文件读写encoding/hex- 十六进制编解码encoding/json- JSON 编解码encoding/xml- XML 编解码encoding/asn1- ASN.1 编解码encoding/gob- Gob 二进制序列化encoding/pem- PEM 编解码
重要说明:
- ⚠️ 接口定义:
encoding包本身主要定义接口 - ⚠️ 子包实现:具体编解码功能在子包中实现
- ✅ 标准库支持:Go 标准库提供完整支持
- ✅ 类型安全:编译时检查类型
核心接口:
// 文本编解码器
type TextMarshaler interface {
MarshalText() (text []byte, err error)
}
type TextUnmarshaler interface {
UnmarshalText(text []byte) error
}
// 二进制编解码器
type BinaryMarshaler interface {
MarshalBinary() (data []byte, err error)
}
type BinaryUnmarshaler interface {
UnmarshalBinary(data []byte) error
}
核心接口
1. TextMarshaler - 文本编组器
type TextMarshaler interface {
MarshalText() (text []byte, err error)
}
功能:将值转换为文本格式。
实现示例:
type Color struct {
R, G, B uint8
}
func (c Color) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("#%02x%02x%02x", c.R, c.G, c.B)), nil
}
使用场景:
- ✅ 自定义类型的文本表示
- ✅ JSON 编码(作为 string)
- ✅ XML 编码
- ✅ 配置文件
2. TextUnmarshaler - 文本解组器
type TextUnmarshaler interface {
UnmarshalText(text []byte) error
}
功能:从文本格式解析值。
实现示例:
func (c *Color) UnmarshalText(text []byte) error {
if len(text) != 7 || text[0] != '#' {
return fmt.Errorf("无效的颜色格式")
}
r, err := strconv.ParseUint(string(text[1:3]), 16, 8)
if err != nil {
return err
}
g, err := strconv.ParseUint(string(text[3:5]), 16, 8)
if err != nil {
return err
}
b, err := strconv.ParseUint(string(text[5:7]), 16, 8)
if err != nil {
return err
}
c.R = uint8(r)
c.G = uint8(g)
c.B = uint8(b)
return nil
}
使用场景:
- ✅ 解析自定义文本格式
- ✅ JSON 解码(从 string)
- ✅ XML 解码
- ✅ 配置文件解析
3. BinaryMarshaler - 二进制编组器
type BinaryMarshaler interface {
MarshalBinary() (data []byte, err error)
}
功能:将值转换为二进制格式。
实现示例:
type Point struct {
X, Y int32
}
func (p Point) MarshalBinary() ([]byte, error) {
buf := make([]byte, 8)
binary.LittleEndian.PutUint32(buf[0:4], uint32(p.X))
binary.LittleEndian.PutUint32(buf[4:8], uint32(p.Y))
return buf, nil
}
使用场景:
- ✅ 高效的二进制序列化
- ✅ 网络传输
- ✅ 数据存储
- ✅ 缓存
4. BinaryUnmarshaler - 二进制解组器
type BinaryUnmarshaler interface {
UnmarshalBinary(data []byte) error
}
功能:从二进制格式解析值。
实现示例:
func (p *Point) UnmarshalBinary(data []byte) error {
if len(data) != 8 {
return fmt.Errorf("数据长度错误")
}
p.X = int32(binary.LittleEndian.Uint32(data[0:4]))
p.Y = int32(binary.LittleEndian.Uint32(data[4:8]))
return nil
}
使用场景:
- ✅ 解析二进制数据
- ✅ 网络数据接收
- ✅ 数据加载
- ✅ 缓存读取
encoding/base32 - Base32 编解码
概述
Base32 是一种使用 32 个字符表示二进制数据的编码方式。
特点:
- ✅ 不区分大小写
- ✅ 只使用字母和数字(A-Z, 2-7)
- ✅ 适合口头传输
- ⚠️ 比 Base64 占用更多空间(约 20%)
核心类型
// 编码器
type Encoding struct{}
// 预定义的编码
const (
StdEncoding = stdEncoding // 标准 Base32
HexEncoding = hexEncoding // Base32hex(扩展十六进制)
)
基本使用
package main
import (
"encoding/base32"
"fmt"
)
func main() {
data := []byte("Hello, World!")
// 编码
encoded := base32.StdEncoding.EncodeToString(data)
fmt.Printf("编码:%s\n", encoded)
// 解码
decoded, err := base32.StdEncoding.DecodeString(encoded)
if err != nil {
fmt.Printf("解码失败:%v\n", err)
return
}
fmt.Printf("解码:%s\n", string(decoded))
}
使用流式编码
package main
import (
"encoding/base32"
"os"
"strings"
)
func main() {
// 编码
var encoded strings.Builder
encoder := base32.NewEncoder(base32.StdEncoding, &encoded)
encoder.Write([]byte("Hello, World!"))
encoder.Close()
// 解码
reader := base32.NewDecoder(base32.StdEncoding, strings.NewReader(encoded.String()))
decoded := make([]byte, 100)
n, _ := reader.Read(decoded)
os.Stdout.Write(decoded[:n])
}
encoding/base64 - Base64 编解码
概述
Base64 是最常用的二进制到文本的编码方式。
特点:
- ✅ 使用 64 个字符(A-Z, a-z, 0-9, +, /)
- ✅ 紧凑(增加约 33% 大小)
- ✅ 广泛应用(Data URI、邮件附件等)
- ⚠️ 包含特殊字符(+ 和 /)
核心类型
// 编码器
type Encoding struct{}
// 预定义的编码
const (
StdEncoding = stdEncoding // 标准 Base64
URLEncoding = urlEncoding // URL 安全 Base64(- 和 _)
RawStdEncoding = rawStdEncoding // 无填充标准 Base64
RawURLEncoding = rawURLEncoding // 无填充 URL 安全 Base64
)
基本使用
package main
import (
"encoding/base64"
"fmt"
)
func main() {
data := []byte("Hello, World!")
// 标准编码
encoded := base64.StdEncoding.EncodeToString(data)
fmt.Printf("标准编码:%s\n", encoded)
// URL 安全编码
urlEncoded := base64.URLEncoding.EncodeToString(data)
fmt.Printf("URL 编码:%s\n", urlEncoded)
// 标准解码
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
fmt.Printf("解码失败:%v\n", err)
return
}
fmt.Printf("解码:%s\n", string(decoded))
}
Data URI 示例
package main
import (
"encoding/base64"
"fmt"
"net/http"
)
func main() {
// 读取图片
imageData := []byte{ /* PNG 数据 */ }
// 创建 Data URI
encoded := base64.StdEncoding.EncodeToString(imageData)
dataURI := fmt.Sprintf("data:image/png;base64,%s", encoded)
// 在 HTML 中使用
html := fmt.Sprintf(`<img src="%s" alt="Embedded Image">`, dataURI)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
w.Write([]byte(html))
})
http.ListenAndServe(":8080", nil)
}
流式编码
package main
import (
"encoding/base64"
"os"
"strings"
)
func encodeFile(filename string) (string, error) {
data, err := os.ReadFile(filename)
if err != nil {
return "", err
}
var encoded strings.Builder
encoder := base64.NewEncoder(base64.StdEncoding, &encoded)
defer encoder.Close()
encoder.Write(data)
return encoded.String(), nil
}
func decodeFile(encoded string, output string) error {
reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encoded))
data, err := os.ReadAll(reader)
if err != nil {
return err
}
return os.WriteFile(output, data, 0644)
}
encoding/binary - 二进制编解码
概述
encoding/binary 包提供了二进制和数字之间的转换功能。
主要功能:
- 🔢 数字和字节片的转换
- 📊 结构体的二进制序列化
- 🔀 字节序处理(大端/小端)
核心函数
// 字节序
var (
BigEndian bigEndian
LittleEndian littleEndian
// HostEndian // 主机字节序
)
// 基本类型转换
func PutUint16(b []byte, v uint16)
func PutUint32(b []byte, v uint32)
func PutUint64(b []byte, v uint64)
func PutVarint(b []byte, x int64) int
func Uint16(b []byte) uint16
func Uint32(b []byte) uint32
func Uint64(b []byte) uint64
func Varint(b []byte) (int64, int)
// 读写接口
func Read(r io.Reader, data interface{}) error
func Write(w io.Writer, data interface{}) error
func Size(v interface{}) int
// 编码解码器
type ByteOrder interface {
Uint16([]byte) uint16
Uint32([]byte) uint32
Uint64([]byte) uint64
PutUint16([]byte, uint16)
PutUint32([]byte, uint32)
PutUint64([]byte, uint64)
String() string
}
基本类型转换
package main
import (
"encoding/binary"
"fmt"
)
func main() {
// 小端编码
buf := make([]byte, 8)
binary.LittleEndian.PutUint32(buf[0:4], 0x12345678)
binary.LittleEndian.PutUint32(buf[4:8], 0xDEADBEEF)
fmt.Printf("小端:%x\n", buf)
// 大端编码
binary.BigEndian.PutUint32(buf[0:4], 0x12345678)
binary.BigEndian.PutUint32(buf[4:8], 0xDEADBEEF)
fmt.Printf("大端:%x\n", buf)
// 解码
v1 := binary.LittleEndian.Uint32(buf[0:4])
v2 := binary.LittleEndian.Uint32(buf[4:8])
fmt.Printf("值:%x, %x\n", v1, v2)
}
结构体序列化
package main
import (
"bytes"
"encoding/binary"
"fmt"
"log"
)
// 数据包结构
type Packet struct {
Magic uint16
Version uint8
Type uint8
Length uint32
Data []byte
}
// 序列化
func (p *Packet) Marshal() ([]byte, error) {
buf := new(bytes.Buffer)
// 写入固定字段
err := binary.Write(buf, binary.LittleEndian, p.Magic)
if err != nil {
return nil, err
}
err = binary.Write(buf, binary.LittleEndian, p.Version)
if err != nil {
return nil, err
}
err = binary.Write(buf, binary.LittleEndian, p.Type)
if err != nil {
return nil, err
}
err = binary.Write(buf, binary.LittleEndian, p.Length)
if err != nil {
return nil, err
}
// 写入数据
_, err = buf.Write(p.Data)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// 反序列化
func UnmarshalPacket(data []byte) (*Packet, error) {
buf := bytes.NewReader(data)
packet := &Packet{}
err := binary.Read(buf, binary.LittleEndian, &packet.Magic)
if err != nil {
return nil, err
}
err = binary.Read(buf, binary.LittleEndian, &packet.Version)
if err != nil {
return nil, err
}
err = binary.Read(buf, binary.LittleEndian, &packet.Type)
if err != nil {
return nil, err
}
err = binary.Read(buf, binary.LittleEndian, &packet.Length)
if err != nil {
return nil, err
}
// 读取数据
packet.Data = make([]byte, packet.Length)
_, err = buf.Read(packet.Data)
if err != nil {
return nil, err
}
return packet, nil
}
func main() {
packet := &Packet{
Magic: 0x1234,
Version: 1,
Type: 2,
Length: 13,
Data: []byte("Hello, World!"),
}
// 序列化
data, err := packet.Marshal()
if err != nil {
log.Fatal(err)
}
fmt.Printf("序列化:%x\n", data)
// 反序列化
decoded, err := UnmarshalPacket(data)
if err != nil {
log.Fatal(err)
}
fmt.Printf("反序列化:%+v\n", decoded)
}
变长整数(Varint)
package main
import (
"encoding/binary"
"fmt"
)
func main() {
buf := make([]byte, binary.MaxVarintLen64)
// 编码
n := binary.PutVarint(buf, 12345)
fmt.Printf("编码长度:%d\n", n)
fmt.Printf("编码数据:%x\n", buf[:n])
// 解码
value, size := binary.Varint(buf[:n])
fmt.Printf("解码值:%d, 长度:%d\n", value, size)
// Uvarint(无符号)
n = binary.PutUvarint(buf, 67890)
fmt.Printf("Uvarint 编码:%x\n", buf[:n])
value, size = binary.Uvarint(buf[:n])
fmt.Printf("Uvarint 解码:%d, 长度:%d\n", value, size)
}
encoding/csv - CSV 文件读写
概述
encoding/csv 包提供了 CSV(逗号分隔值)文件的读写功能。
特点:
- ✅ 标准 CSV 格式支持
- ✅ 自动处理引号和转义
- ✅ 支持自定义分隔符
- ✅ 流式读写
核心类型
// 读取器
type Reader struct {
Comma rune // 字段分隔符
Comment rune // 注释字符
FieldsPerRecord int // 每行字段数(-1=可变)
LazyQuotes bool // 允许不匹配的引号
TrimLeadingSpace bool // 修剪前导空格
ReuseRecord bool // 重用记录缓冲区
}
func NewReader(r io.Reader) *Reader
// 写入器
type Writer struct {
Comma rune // 字段分隔符
UseCRLF bool // 使用 \r\n 换行
}
func NewWriter(w io.Writer) *Writer
读取 CSV 文件
package main
import (
"encoding/csv"
"fmt"
"log"
"os"
)
func main() {
// 打开文件
file, err := os.Open("data.csv")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 创建读取器
reader := csv.NewReader(file)
// 可选配置
reader.Comma = ',' // 分隔符
reader.Comment = '#' // 注释字符
reader.FieldsPerRecord = -1 // 允许字段数可变
// 读取所有记录
records, err := reader.ReadAll()
if err != nil {
log.Fatal(err)
}
// 处理数据
for i, record := range records {
if i == 0 {
fmt.Println("表头:", record)
continue
}
fmt.Printf("第 %d 行:", i)
for j, field := range record {
fmt.Printf(" 字段%d: %s", j, field)
}
fmt.Println()
}
}
流式读取
package main
import (
"encoding/csv"
"fmt"
"io"
"log"
"os"
)
func main() {
file, err := os.Open("large_data.csv")
if err != nil {
log.Fatal(err)
}
defer file.Close()
reader := csv.NewReader(file)
// 逐行读取
lineNum := 0
for {
record, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
lineNum++
fmt.Printf("第 %d 行:%v\n", lineNum, record)
}
}
写入 CSV 文件
package main
import (
"encoding/csv"
"log"
"os"
)
func main() {
// 创建文件
file, err := os.Create("output.csv")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 创建写入器
writer := csv.NewWriter(file)
defer writer.Flush()
// 可选配置
writer.Comma = ','
writer.UseCRLF = false
// 写入表头
header := []string{"姓名", "年龄", "城市"}
if err := writer.Write(header); err != nil {
log.Fatal(err)
}
// 写入数据
records := [][]string{
{"张三", "25", "北京"},
{"李四", "30", "上海"},
{"王五", "28", "广州"},
}
for _, record := range records {
if err := writer.Write(record); err != nil {
log.Fatal(err)
}
}
}
自定义 CSV 格式
package main
import (
"encoding/csv"
"fmt"
"log"
"strings"
)
func main() {
// TSV 格式(制表符分隔)
tsvData := "姓名\t年龄\t城市\n张三\t25\t北京\n李四\t30\t上海"
reader := csv.NewReader(strings.NewReader(tsvData))
reader.Comma = '\t'
records, err := reader.ReadAll()
if err != nil {
log.Fatal(err)
}
fmt.Println("TSV 数据:")
for _, record := range records {
fmt.Println(record)
}
// 分号分隔
csvData := "姓名;年龄;城市\n张三;25;北京"
reader = csv.NewReader(strings.NewReader(csvData))
reader.Comma = ';'
records, err = reader.ReadAll()
if err != nil {
log.Fatal(err)
}
fmt.Println("\n分号分隔:")
for _, record := range records {
fmt.Println(record)
}
}
encoding/hex - 十六进制编解码
概述
encoding/hex 包提供了十六进制编码和解码功能。
特点:
- ✅ 人类可读
- ✅ 调试友好
- ⚠️ 空间效率低(2 倍大小)
核心函数
// 编码
func Encode(dst, src []byte) int
func EncodeToString(src []byte) string
// 解码
func Decode(dst, src []byte) (int, error)
func DecodeString(s string) ([]byte, error)
// 解码器
type InvalidByteError byte
基本使用
package main
import (
"encoding/hex"
"fmt"
)
func main() {
data := []byte("Hello, World!")
// 编码为字符串
encoded := hex.EncodeToString(data)
fmt.Printf("编码:%s\n", encoded)
// 解码
decoded, err := hex.DecodeString(encoded)
if err != nil {
fmt.Printf("解码失败:%v\n", err)
return
}
fmt.Printf("解码:%s\n", string(decoded))
// 直接编码到缓冲区
buf := make([]byte, hex.EncodedLen(len(data)))
hex.Encode(buf, data)
fmt.Printf("缓冲区编码:%s\n", string(buf))
// 直接解码到缓冲区
decodedBuf := make([]byte, hex.DecodedLen(len(buf)))
n, err := hex.Decode(decodedBuf, buf)
if err != nil {
fmt.Printf("解码失败:%v\n", err)
return
}
fmt.Printf("缓冲区解码:%s\n", string(decodedBuf[:n]))
}
使用示例
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
)
// 计算 MD5 哈希(十六进制表示)
func MD5Hash(data []byte) string {
hash := md5.Sum(data)
return hex.EncodeToString(hash[:])
}
func main() {
data := []byte("Hello, World!")
hash := MD5Hash(data)
fmt.Printf("原始数据:%s\n", string(data))
fmt.Printf("MD5 哈希:%s\n", hash)
// 验证哈希
decoded, _ := hex.DecodeString(hash)
fmt.Printf("哈希字节:%x\n", decoded)
}
总结
核心接口
| 接口 | 方法 | 用途 |
|---|---|---|
| TextMarshaler | MarshalText() | 文本编组 |
| TextUnmarshaler | UnmarshalText() | 文本解组 |
| BinaryMarshaler | MarshalBinary() | 二进制编组 |
| BinaryUnmarshaler | UnmarshalBinary() | 二进制解组 |
子包对比
| 子包 | 编码格式 | 空间效率 | 人类可读 | 主要用途 |
|---|---|---|---|---|
| base32 | Base32 | +60% | ✅ | 文件名、口头传输 |
| base64 | Base64 | +33% | ✅ | Data URI、邮件附件 |
| binary | 二进制 | 100% | ❌ | 网络协议、文件存储 |
| csv | CSV | ~100% | ✅ | 数据交换、表格 |
| hex | 十六进制 | +100% | ✅ | 调试、哈希显示 |
| json | JSON | ~100% | ✅ | Web API、配置 |
| xml | XML | ~100% | ✅ | Web 服务、文档 |
| asn1 | ASN.1 | 高效 | ❌ | 证书、加密 |
| gob | Gob | 高效 | ❌ | Go 程序间通信 |
| pem | PEM | +33% | ✅ | 证书、密钥 |
使用场景
| 场景 | 推荐包 | 说明 |
|---|---|---|
| URL 安全编码 | encoding/base64 | 使用 URLEncoding |
| 文件完整性校验 | encoding/hex | MD5/SHA 哈希显示 |
| 网络协议 | encoding/binary | 高效二进制传输 |
| 数据导出 | encoding/csv | 表格数据交换 |
| Web API | encoding/json | RESTful API |
| 配置文件 | encoding/json | 结构化配置 |
| 证书处理 | encoding/pem | PEM 格式证书 |
| Go 程序通信 | encoding/gob | Go 特有格式 |
参考资料
- Go encoding 包文档
- encoding/base32 文档
- encoding/base64 文档
- encoding/binary 文档
- encoding/csv 文档
- encoding/hex 文档
- encoding/json 文档
- encoding/xml 文档
- encoding/asn1 文档
- encoding/gob 文档
- encoding/pem 文档
最后更新:2026-04-03
Go 版本:Go 1.23+