encoding/binary is a Go standard library package for encoding/decoding fixed-size numeric data (and structs made of fixed-size fields) to/from raw bytes—often used when you need a specific binary layout for files, network protocols, or hardware formats.
binary /ˈbaɪnəri/ = nhị phân
encode /ɪnˈkoʊd/ = mã hoá (đóng gói dữ liệu)
decode /diːˈkoʊd/ = giải mã (mở gói dữ liệu)
fixed-size /ˌfɪkst ˈsaɪz/ = kích thước cố định
raw bytes /rɔː baɪts/ = byte thô
Use encoding/binary when you want to:
Read/write numbers in a specific endianness (Little/Big endian) from/to a []byte or stream.
Serialize/deserialize simple structs with fixed-size numeric fields (careful with padding/alignment).
Implement or parse binary protocols (e.g., custom TCP protocol headers).
Work with binary file formats (headers, frames, records).
endianness /en.di.ˈæn.nəs/ = thứ tự sắp byte (little/big endian)
protocol /ˈproʊtəˌkɔːl/ = giao thức
serialize /ˈsɪrəˌlaɪz/ = tuần tự hoá (biến dữ liệu thành chuỗi byte)
encoding/binary is not ideal for:
Complex object serialization (maps with variable lengths, nested slices, strings, etc.).
Cross-language “general-purpose” formats (use protobuf/CBOR/MessagePack/JSON depending on needs).
Human-readable output.
Why:
binary.Write/binary.Read require fixed-size types.
Strings/slices need a length prefix you must design yourself.
encoding/binary exposes byte orders:
binary.LittleEndian
binary.BigEndian
Rule of thumb:
Many network protocols use Big Endian (“network byte order”).
Many CPU-native/file formats may use Little Endian.
network byte order /ˈnetˌwɝːk baɪt ˈɔːrdər/ = thứ tự byte chuẩn mạng
import "encoding/binary" var x uint32 = 0x11223344 buf := make([]byte, 4) binary.BigEndian.PutUint32(buf, x) // [11 22 33 44] in hex binary.LittleEndian.PutUint32(buf, x) // [44 33 22 11] in hex
Use PutUintXX / UintXX for fast conversion.
b := make([]byte, 8) binary.LittleEndian.PutUint16(b[0:2], 513) // write v16 := binary.LittleEndian.Uint16(b[0:2]) // read binary.BigEndian.PutUint64(b[0:8], 123456789) // write v64 := binary.BigEndian.Uint64(b[0:8]) // read
uint16/uint64 /ˌjuːɪnt sɪkˈstiːn/ = số nguyên không dấu 16/64-bit
These operate on an io.Reader / io.Writer and encode/decode using a chosen byte order.
Signatures (conceptually):
binary.Read(r io.Reader, order ByteOrder, data any) error
binary.Write(w io.Writer, order ByteOrder, data any) error
stream /striːm/ = luồng dữ liệu
reader /ˈriːdər/ = bộ đọc
writer /ˈraɪtər/ = bộ ghi
Important constraints:
Fields should be fixed-size numeric types (e.g., uint32, int16, [16]byte).
Avoid string, []byte (variable length) inside the struct.
package main import ( "bytes" "encoding/binary" "fmt" ) type Header struct { Magic [4]byte // fixed-size array is OK Version uint16 Flags uint16 Length uint32 } func main() { h := Header{ Magic: [4]byte{'D', 'A', 'T', 'A'}, Version: 1, Flags: 0, Length: 1024, } var buf bytes.Buffer // Write header in Big Endian _ = binary.Write(&buf, binary.BigEndian, h) // Read it back var h2 Header _ = binary.Read(&buf, binary.BigEndian, &h2) fmt.Println(string(h2.Magic[:]), h2.Version, h2.Length) }
A common simple message layout:
4 bytes: magic
2 bytes: version
4 bytes: payload length
N bytes: payload
Why:
Fixed header makes parsing easy.
Length tells you how many bytes to read next.
You usually do:
Write length (fixed-size integer)
Write raw bytes
func WriteBytes(w *bytes.Buffer, p []byte) error { if err := binary.Write(w, binary.BigEndian, uint32(len(p))); err != nil { return err } _, err := w.Write(p) return err }
length prefix /leŋkθ ˈpriːfɪks/ = tiền tố độ dài
func ReadBytes(r *bytes.Reader) ([]byte, error) { var n uint32 if err := binary.Read(r, binary.BigEndian, &n); err != nil { return nil, err } p := make([]byte, n) _, err := r.Read(p) return p, err }
Tip: for real streams, prefer io.ReadFull to ensure you read exactly n bytes.
Structs may include padding due to alignment; that can break “expected layout” across compilers/architectures.
Safer: manually write each field in order.
binary.Read/Write can be slower than manual PutUintXX for hot paths.
Always define your protocol endianness explicitly (don’t rely on machine).
padding /ˈpædɪŋ/ = byte đệm
alignment /əˈlaɪnmənt/ = căn hàng bộ nhớ
explicitly /ɪkˈsplɪsɪtli/ = một cách rõ ràng
binary.BigEndian / binary.LittleEndian — choose byte order
PutUint16/32/64 + Uint16/32/64 — fast byte-slice number encode/decode
binary.Read / binary.Write — read/write fixed-size values (or structs) from/to streams
Use encoding/gob when: Go-to-Go object serialization (not a fixed binary protocol)
Use encoding/json when: human-readable, interoperable text format