2015-07-21 90 views
0

我正在尋找乾淨的方式將字節數組轉換爲客戶機 - 服務器應用程序的結構體。 我知道大多數ppl轉向採用這種解決方案的gob包,但是我不控制應用程序的編碼。這就是說,我只編寫服務器應用程序而不是客戶端,有一個正在交換的協議的相互協議。golang將字節數組轉換爲結構體

我可以出來的最好的是以下。

type T struct { 
    A int16 
    B int8 
    C []byte 
} 

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

    buf1 := []byte{5, 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 playground

+0

你只是控制服務器端,意味着你已經有串行協議。你有什麼協議,是你問題的關鍵。 golang擁有對廣泛使用的協議(如JSON,BSON或PROTOBUF)的編碼包支持。因此找出串行協議並選擇編碼包。或者如果您有私人協議,請自行實施編碼。 –

+0

這是私人協議。任何示例/文章/ goplayground? – user642318

回答

0

由於您使用的是私有協議。實施自己的協議是個好主意。有很多examplesofhow來做到這一點。

您只受到編碼器實現的限制。我建議查看json.Decoder來處理緩衝區,而不是看直接的字節片。這些操作在緩衝區上,對於大數據流非常有用。

+0

私有協議實際上不是以文本的形式(如json),而是在邏輯上以字節表示。事實上,在一些切片中,比特在這些協議中被表示爲標誌。任何指導哪裏會是一個更好的例子? – user642318

1

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

數據必須指向一個固定大小的值或一片固定大小值。

所以你不能在你的結構採用分片[]byte。但是你可以使用固定大小的數組。
像這樣:Go playground

+0

任何想法如何轉換爲可變大小 – user642318

+0

取決於您的數據結構。你可以將源數組分成兩部分。第一部分將只包含固定大小的數據(在你的情況下爲3字節的A和B)。第二部分將包含數組數據。用這種方法,你需要創建新的結構,而不需要數組部分,就像'類型T結構'int16 \t B int8 }'。並分別解碼這兩個部分 – RoninDev

0

我認爲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) 
}