Skip to content
Go
encoding/xml · encoding/csv...

encoding/xml · encoding/csv · encoding/base64

1. encoding/xml

1.1 基础用法

type User struct {
    XMLName xml.Name `xml:"user"`
    ID      int      `xml:"id,attr"`        // 属性
    Name    string   `xml:"name"`           // 子元素
    Email   string   `xml:"email,omitempty"`
    Roles   []string `xml:"roles>role"`     // 嵌套:<roles><role>admin</role></roles>
    Active  bool     `xml:"active,attr,omitempty"` // 属性 + 零值忽略
}

// 序列化
user := User{ID: 1, Name: "Alice", Roles: []string{"admin", "user"}}
data, _ := xml.MarshalIndent(user, "", "  ")
fmt.Println(xml.Header + string(data))
// <?xml version="1.0" encoding="UTF-8"?>
// <user id="1">
//   <name>Alice</name>
//   <roles>
//     <role>admin</role>
//     <role>user</role>
//   </roles>
// </user>

1.2 流式 XML 解析

Go 的 XML 解析器是**拉模式(Pull-based)**的,与 SAX(push-based)和 DOM 都不同:

decoder := xml.NewDecoder(strings.NewReader(xmlData))

for {
    token, err := decoder.Token()
    if err == io.EOF {
        break
    }
    switch t := token.(type) {
    case xml.StartElement:
        fmt.Printf("开始元素: %s\n", t.Name.Local)
        for _, attr := range t.Attr {
            fmt.Printf("  属性: %s=%s\n", attr.Name.Local, attr.Value)
        }
    case xml.EndElement:
        fmt.Printf("结束元素: %s\n", t.Name.Local)
    case xml.CharData:
        if s := strings.TrimSpace(string(t)); s != "" {
            fmt.Printf("  内容: %s\n", s)
        }
    case xml.Comment:
        fmt.Printf("  注释: %s\n", t)
    }
}

1.3 XML 标签与命名空间

// 命名空间
type Envelope struct {
    XMLName xml.Name `xml:"http://example.com/ns soap:Envelope"`
    Body    Body
}

// CDATA
type Content struct {
    Text string `xml:",cdata"`
}

// 内嵌(不产生额外层级)
type Item struct {
    XMLName xml.Name `xml:"item"`
    Content string   `xml:",innerxml"` // 保留内部原始 XML
}

现实情况:Go 的 encoding/xml 在处理命名空间和复杂 SOAP/XML Schema 时非常吃力。大多数 Go 项目倾向于 JSON/Protobuf 而不是 XML。


2. encoding/csv

2.1 读写 CSV

// 写入
var buf bytes.Buffer
writer := csv.NewWriter(&buf)

records := [][]string{
    {"name", "age", "city"},
    {"Alice", "30", "New York"},
}
writer.WriteAll(records)
writer.Flush() // 必须 flush

// 读取
reader := csv.NewReader(&buf)
reader.TrimLeadingSpace = true
reader.ReuseRecord = true   // 复用 []string 减少分配

for {
    record, err := reader.Read()
    if err == io.EOF {
        break
    }
    fmt.Println(record) // [name age city] ...
}

2.2 自定义分隔符(TSV)

// TSV(制表符分隔)
reader := csv.NewReader(strings.NewReader(tsvData))
reader.Comma = '\t'       // ← 改为制表符
reader.Comment = '#'      // 注释行
reader.FieldsPerRecord = -1 // 可变字段数
reader.LazyQuotes = true   // 允许不配对引号

2.3 处理大 CSV 文件

file, _ := os.Open("large.csv")
reader := csv.NewReader(file)

// 读头部建立列索引
header, _ := reader.Read()
colIndex := make(map[string]int)
for i, name := range header {
    colIndex[name] = i
}

for {
    record, err := reader.Read()
    if err == io.EOF {
        break
    }
    name := record[colIndex["name"]]
    age := record[colIndex["age"]]
    process(name, age)
}

3. encoding/base64

3.1 三种编码模式

data := []byte("Hello, 世界")

// Standard — 标准 Base64(RFC 4648)
standard := base64.StdEncoding.EncodeToString(data)
// → "SGVsbG8sIOS4lueVjA=="

// URL — URL 安全(用 - 和 _ 代替 + 和 /)
urlSafe := base64.URLEncoding.EncodeToString(data)
// → "SGVsbG8sIOS4lueVjA=="

// RawStd — 无填充(省略末尾 =)
raw := base64.RawStdEncoding.EncodeToString(data)
// → "SGVsbG8sIOS4lueVjA"

// 对应的解码方式
base64.StdEncoding.DecodeString(standard)
base64.URLEncoding.DecodeString(urlSafe)
base64.RawStdEncoding.DecodeString(raw)

💡 使用指南

  • API token / JWT → RawURLEncoding(URL 安全 + 无填充)。
  • 数据库存储 → StdEncoding
  • 文件名 → RawURLEncoding

3.2 流式编码

var buf bytes.Buffer
encoder := base64.NewEncoder(base64.StdEncoding, &buf)
encoder.Write([]byte("chunk1"))
encoder.Write([]byte("chunk2"))
encoder.Close() // 必须调用:写入填充并 flush
fmt.Println(buf.String())

// 流式解码
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(buf.String()))
io.Copy(os.Stdout, decoder)

4. 🚨 常见陷阱

陷阱 说明
CSV Writer 未 Flush 数据留在缓冲区未写入底层 Writer
XML 的默认命名空间 Go 的 XML 解析对默认命名空间支持不佳
Base64 不同编码混用 StdEncoding 编码的数据不能用 URLEncoding 解码
CSV 字段中有逗号/换行 CSV Writer 会自动加引号,但需确保 Reader 的 LazyQuotes 匹配