Encoding and Decoding Data in Go
Encoding and decoding are essential for data transformation and transmission. Go provides comprehensive support for various encoding formats. This guide covers practical encoding and decoding techniques.
Base64 Encoding
Basic Base64 Operations
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Encode to base64
data := "Hello, World!"
encoded := base64.StdEncoding.EncodeToString([]byte(data))
fmt.Println("Encoded:", encoded)
// Decode from base64
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Decoded:", string(decoded))
}
URL-Safe Base64
package main
import (
"encoding/base64"
"fmt"
)
func main() {
data := "Hello, World!"
// URL-safe encoding
encoded := base64.URLEncoding.EncodeToString([]byte(data))
fmt.Println("URL-safe encoded:", encoded)
// URL-safe decoding
decoded, _ := base64.URLEncoding.DecodeString(encoded)
fmt.Println("Decoded:", string(decoded))
}
Hex Encoding
Hex Operations
package main
import (
"encoding/hex"
"fmt"
)
func main() {
// Encode to hex
data := "Hello, World!"
encoded := hex.EncodeToString([]byte(data))
fmt.Println("Hex encoded:", encoded)
// Decode from hex
decoded, err := hex.DecodeString(encoded)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Decoded:", string(decoded))
}
JSON Encoding
JSON Marshaling
package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
user := User{ID: 1, Name: "Alice", Email: "[email protected]"}
// Marshal to JSON
data, err := json.Marshal(user)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("JSON:", string(data))
// Unmarshal from JSON
var decoded User
err = json.Unmarshal(data, &decoded)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Decoded: %+v\n", decoded)
}
Pretty JSON
package main
import (
"encoding/json"
"fmt"
)
func main() {
user := map[string]interface{}{
"id": 1,
"name": "Alice",
"email": "[email protected]",
}
// Pretty print JSON
data, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(data))
}
Custom Encoding
Custom Marshaler
package main
import (
"encoding/json"
"fmt"
"time"
)
type Event struct {
Name string
Timestamp time.Time
}
// Custom JSON marshaling
func (e Event) MarshalJSON() ([]byte, error) {
type Alias Event
return json.Marshal(&struct {
Timestamp string `json:"timestamp"`
*Alias
}{
Timestamp: e.Timestamp.Format(time.RFC3339),
Alias: (*Alias)(&e),
})
}
// Custom JSON unmarshaling
func (e *Event) UnmarshalJSON(data []byte) error {
type Alias Event
aux := &struct {
Timestamp string `json:"timestamp"`
*Alias
}{
Alias: (*Alias)(e),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
t, err := time.Parse(time.RFC3339, aux.Timestamp)
if err != nil {
return err
}
e.Timestamp = t
return nil
}
func main() {
event := Event{
Name: "Conference",
Timestamp: time.Now(),
}
// Marshal
data, _ := json.MarshalIndent(event, "", " ")
fmt.Println("Encoded:", string(data))
// Unmarshal
var decoded Event
json.Unmarshal(data, &decoded)
fmt.Printf("Decoded: %+v\n", decoded)
}
Binary Encoding
Binary Serialization
package main
import (
"bytes"
"encoding/binary"
"fmt"
)
func main() {
// Encode integers
var buf bytes.Buffer
// Write int32
binary.Write(&buf, binary.LittleEndian, int32(42))
// Write float64
binary.Write(&buf, binary.LittleEndian, 3.14)
fmt.Println("Encoded bytes:", buf.Bytes())
// Decode
var num int32
var pi float64
binary.Read(&buf, binary.LittleEndian, &num)
binary.Read(&buf, binary.LittleEndian, &pi)
fmt.Printf("Number: %d, Pi: %f\n", num, pi)
}
Practical Examples
Data Compression
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io"
)
func compressData(data []byte) ([]byte, error) {
var buf bytes.Buffer
writer := gzip.NewWriter(&buf)
_, err := writer.Write(data)
if err != nil {
return nil, err
}
writer.Close()
return buf.Bytes(), nil
}
func decompressData(data []byte) ([]byte, error) {
reader, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
}
defer reader.Close()
return io.ReadAll(reader)
}
func main() {
original := []byte("Hello, World! This is a test message.")
// Compress
compressed, _ := compressData(original)
fmt.Printf("Original size: %d, Compressed size: %d\n", len(original), len(compressed))
// Decompress
decompressed, _ := decompressData(compressed)
fmt.Println("Decompressed:", string(decompressed))
}
Protocol Buffer-like Encoding
package main
import (
"bytes"
"encoding/binary"
"fmt"
)
type Message struct {
ID uint32
Name string
Score float32
}
func (m *Message) Encode() ([]byte, error) {
var buf bytes.Buffer
// Write ID
binary.Write(&buf, binary.LittleEndian, m.ID)
// Write name length and data
binary.Write(&buf, binary.LittleEndian, uint32(len(m.Name)))
buf.WriteString(m.Name)
// Write score
binary.Write(&buf, binary.LittleEndian, m.Score)
return buf.Bytes(), nil
}
func (m *Message) Decode(data []byte) error {
buf := bytes.NewReader(data)
// Read ID
binary.Read(buf, binary.LittleEndian, &m.ID)
// Read name
var nameLen uint32
binary.Read(buf, binary.LittleEndian, &nameLen)
nameBytes := make([]byte, nameLen)
buf.Read(nameBytes)
m.Name = string(nameBytes)
// Read score
binary.Read(buf, binary.LittleEndian, &m.Score)
return nil
}
func main() {
msg := Message{ID: 1, Name: "Alice", Score: 95.5}
// Encode
encoded, _ := msg.Encode()
fmt.Println("Encoded:", encoded)
// Decode
var decoded Message
decoded.Decode(encoded)
fmt.Printf("Decoded: %+v\n", decoded)
}
CSV Encoding
package main
import (
"bytes"
"encoding/csv"
"fmt"
)
type Record struct {
Name string
Age int
Email string
}
func encodeCSV(records []Record) (string, error) {
var buf bytes.Buffer
writer := csv.NewWriter(&buf)
// Write header
writer.Write([]string{"Name", "Age", "Email"})
// Write records
for _, r := range records {
writer.Write([]string{r.Name, fmt.Sprintf("%d", r.Age), r.Email})
}
writer.Flush()
return buf.String(), nil
}
func main() {
records := []Record{
{"Alice", 30, "[email protected]"},
{"Bob", 25, "[email protected]"},
}
csv, _ := encodeCSV(records)
fmt.Println(csv)
}
Best Practices
โ Good Practices
// Use appropriate encoding for use case
encoded := base64.StdEncoding.EncodeToString(data)
// Handle errors properly
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
// Handle error
}
// Use custom marshalers for complex types
func (t *Type) MarshalJSON() ([]byte, error) {
// Custom logic
}
// Use binary encoding for performance
binary.Write(&buf, binary.LittleEndian, value)
// Validate decoded data
if err := json.Unmarshal(data, &obj); err != nil {
// Handle error
}
โ Anti-Patterns
// Don't ignore encoding errors
encoded, _ := json.Marshal(data)
// Don't use wrong encoding for use case
// Use URL-safe base64 for URLs
// Don't hardcode byte order
// Use binary.LittleEndian or binary.BigEndian
// Don't assume data format
// Always validate decoded data
Resources
- Go encoding Package Documentation
- Go encoding/json Documentation
- Go encoding/base64 Documentation
- Go encoding/hex Documentation
Summary
Encoding and decoding are essential for data transformation:
- Use base64 for text-safe encoding
- Use hex for debugging and display
- Use JSON for structured data
- Use binary for performance
- Handle errors properly
- Validate decoded data
- Use custom marshalers for complex types
With these techniques, you can efficiently encode and decode data in Go applications.
Comments