Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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)
}

总结

核心接口

接口方法用途
TextMarshalerMarshalText()文本编组
TextUnmarshalerUnmarshalText()文本解组
BinaryMarshalerMarshalBinary()二进制编组
BinaryUnmarshalerUnmarshalBinary()二进制解组

子包对比

子包编码格式空间效率人类可读主要用途
base32Base32+60%文件名、口头传输
base64Base64+33%Data URI、邮件附件
binary二进制100%网络协议、文件存储
csvCSV~100%数据交换、表格
hex十六进制+100%调试、哈希显示
jsonJSON~100%Web API、配置
xmlXML~100%Web 服务、文档
asn1ASN.1高效证书、加密
gobGob高效Go 程序间通信
pemPEM+33%证书、密钥

使用场景

场景推荐包说明
URL 安全编码encoding/base64使用 URLEncoding
文件完整性校验encoding/hexMD5/SHA 哈希显示
网络协议encoding/binary高效二进制传输
数据导出encoding/csv表格数据交换
Web APIencoding/jsonRESTful API
配置文件encoding/json结构化配置
证书处理encoding/pemPEM 格式证书
Go 程序通信encoding/gobGo 特有格式

参考资料


最后更新:2026-04-03
Go 版本:Go 1.23+