いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-380 (構造体をそのままバイナリで出力したい)(binary.Write/Read)

関連記事

devlights.hatenablog.com

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。たまにやりたいときに忘れるのでここにメモメモ。

たまーになのですが、構造体の中身をそのままバイナリに出力したいときがあります。(通信で流したいときとか、Cとかから読みたいとか)

注意点は、stringやスライス、マップ、チャネルなどは、そのままでは binary.Writeに通らないという点ですね。つまり、fixed-size である必要があります。なので、文字列などはバイト配列にする必要があります。

サンプル

package main

import (
    "bytes"
    "encoding/binary"
    "encoding/hex"
    "fmt"
    "math"
    "os"
    "unsafe"
)

type St1 struct {
    V1 int32
    V2 uint32
    V3 [8]byte
    V4 uint64
    V5 [8]byte
}

func main() {
    s := St1{}
    fmt.Printf("sizeof=%d, alignof=%d\n", unsafe.Sizeof(s), unsafe.Alignof(s))

    s.V1 = math.MaxInt32
    s.V2 = math.MaxUint32
    copy(s.V3[:], []byte{0xde, 0xad, 0xbe, 0xef})
    s.V4 = math.MaxUint64
    copy(s.V5[:], []byte("hello"))

    //
    // Write
    //
    file, err := os.Create("v1.bin")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    err = binary.Write(file, binary.BigEndian, &s)
    if err != nil {
        panic(err)
    }

    err = file.Sync()
    if err != nil {
        panic(err)
    }

    //
    // Read
    //
    file2, err := os.Open("v1.bin")
    if err != nil {
        panic(err)
    }
    defer file2.Close()

    var s2 St1
    err = binary.Read(file2, binary.BigEndian, &s2)
    if err != nil {
        panic(err)
    }

    //
    // Dump
    //
    var b1, b2 bytes.Buffer

    binary.Write(&b1, binary.BigEndian, s)
    binary.Write(&b2, binary.BigEndian, s2)

    fmt.Println(hex.Dump(b1.Bytes()))
    fmt.Println(hex.Dump(b2.Bytes()))
}

binary.Write() に、&s とポインタを渡していますが、これは実体でもポインタでも大丈夫です。

binary.Write() の中で

reflect.Indirect(reflect.ValueOf(data))

とやっていますので、どちらにせよ指し示す値で処理されます。

逆に、binary.Read()の場合は渡した構造体の中身を変更してもらわないといけないので、ポインタで指定しなければなりません。

$ task run
task: [build] go mod tidy
task: [build] go build -o app main.go
task: [run] ./app
sizeof=32, alignof=8
00000000  7f ff ff ff ff ff ff ff  de ad be ef 00 00 00 00  |................|
00000010  ff ff ff ff ff ff ff ff  68 65 6c 6c 6f 00 00 00  |........hello...|

00000000  7f ff ff ff ff ff ff ff  de ad be ef 00 00 00 00  |................|
00000010  ff ff ff ff ff ff ff ff  68 65 6c 6c 6f 00 00 00  |........hello...|

参考情報

https://pkg.go.dev/encoding/binary@go1.22.0#Write

https://pkg.go.dev/encoding/binary@go1.22.0#Read

Goのおすすめ書籍

上の書籍の日本語版が下です。


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。