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 匹配 |