golang将字节数组转换为结构

Posted

技术标签:

【中文标题】golang将字节数组转换为结构【英文标题】:golang casting byte array to struct 【发布时间】:2015-07-21 01:50:09 【问题描述】:

我正在寻找将字节数组转换为客户端-服务器应用程序结构的干净方法。 我知道大多数人会为此解决方案转向 gob 包,但是我不控制应用程序的编码。话虽如此,我只编写了服务器应用程序而不是客户端,正在交换的协议有一个相互合同。

我能得出的最好的结果如下。

type T struct 
    A int16
    B int8
    C []byte


func main() 
    // Create a struct and write it.
    t := TA: 99, B: 10
    buf := &bytes.Buffer

    buf1 := []byte5, 100, 100
    fmt.Println(buf1)

    buf.Write(buf1)

    //err := binary.Write(buf, binary.BigEndian, t)

    //if err != nil 
    //  panic(err)
    //
    fmt.Println(buf)

    // Read into an empty struct.
    t = T
    err := binary.Read(buf, binary.BigEndian, &t)
    if err != nil 
        panic(err)
    
    fmt.Printf("%d %d", t.A, t.B)

但是,一旦数字字节与结构的大小不一致,go 就会发送一个恐慌。如果尺寸过小或过大,我如何修改它以使其正常工作而不会出现恐慌

Go playground

【问题讨论】:

你只是控制服务器端,意味着你已经有了串口协议。你有什么协议,是你问题的关键。 golang 为广泛使用的协议提供编码包支持,如 JSON、BSON 或 PROTOBUF。所以找出串口协议并选择编码包。或者如果您有私有协议,请自己实现编码。 是私有协议。有没有例子/文章/goplayground? 【参考方案1】:

根据http://golang.org/pkg/encoding/binary/#Read:

数据必须是指向固定大小值或固定大小值切片的指针。

所以你不能在你的结构中使用 slice []byte in。但您可以使用固定大小的数组。 像这样:

package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
)

type T struct 
    A int16
    B int8
    C [256]byte


func main() 
    // Create a struct and write it.
    t := TA: 99, B: 10
    buf := &bytes.Buffer
        
    err := binary.Write(buf, binary.BigEndian, t)
    
    if err != nil 
        panic(err)
    
    fmt.Println(buf)

    // Read into an empty struct.
    t = T
    err = binary.Read(buf, binary.BigEndian, &t)
    if err != nil 
        panic(err)
    
    fmt.Printf("%d %d", t.A, t.B)

Go playground

【讨论】:

知道如何转换为可变大小 取决于你的数据结构。您可以将源数组拆分为 2 个部分。第一部分将仅包含固定大小的数据(A 和 B 在您的情况下为 3 个字节)。第二部分将包含数组数据。这样,您需要创建没有数组部分的新结构,例如type T struct A int16 B int8 。并分别解码两个部分【参考方案2】:

我认为binpacker 会更好地处理这种情况:

package main

import (
    "bytes"
    "fmt"

    "github.com/zhuangsirui/binpacker"
)

type T struct 
    A uint16
    B string
    C []byte


func main() 
    field1 := uint16(1)
    field2 := "Hello World"
    field3 := []byte("Hello World")
    buffer := new(bytes.Buffer)
    binpacker.NewPacker(buffer).
        PushUint16(field1).
        PushUint16(uint16(len(field2))).PushString(field2).
        PushUint16(uint16(len(field3))).PushBytes(field3)

    t := new(T)
    unpacker := binpacker.NewUnpacker(buffer)
    unpacker.FetchUint16(&t.A).StringWithUint16Perfix(&t.B).BytesWithUint16Perfix(&t.C)
    fmt.Println(t)

【讨论】:

以上是关于golang将字节数组转换为结构的主要内容,如果未能解决你的问题,请参考以下文章

将任意 Golang 接口转换为字节数组

golang 在go中将字节数组转换为int

如何在没有副本的情况下将结构转换为字节数组?

从空字节数组转换为结构指针可能会违反严格的别名?

如果我将字节数组转换为 __attribute__((packed, aligned(2))) 结构会发生啥?

将字节数组转换为java类型