首页 > 技术文章 > Go语言的序列化与反序列化(binary) BigEndian LittleEndian

sunlong88 2020-08-02 17:09 原文

encoding/binary包实现了简单的数字(固定长度的数字类型或者只包含定长值的结构体或数组)与字节系列的转换以及变长值的编解码。

func Write(w io.Writer, order ByteOrder, data interface{}) error
序列化,将数据转换成byte字节流,order指定字节序

func Read(r io.Reader, order ByteOrder, data interface{}) error
反序列化,将字节流转换成原始数据

order:
binary.BigEndian(大端模式):内存的低地址存放着数据高位
binary.LittleEndian(小端模式):内存的低地址存放着数据地位

 

big_endian 、little_endian 用于自动改变二进制位存放顺序 
Big Endian and Little Endian 

    谈到字节序的问题,必然牵涉到两大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。那么究竟什么是big endian,什么又是little endian呢? 

     其实big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。 
     用文字说明可能比较抽象,下面用图像加以说明。比如数字0x12345678在两种不同字节序CPU中的存储顺序如下所示:

Big Endian 

   低地址                                             高地址 
   -----------------------------------------> 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
   |      12      |       34     |      56       |      78     | 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

Little Endian 


   低地址                                             高地址 
   -----------------------------------------> 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
   |      78      |       56     |      34       |      12     | 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

     从上面两图可以看出,采用big endian方式存储数据是符合我们人类的思维习惯的。而little endian,!@#$%^&*,见鬼去吧 -_-||| 

     为什么要注意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但是,如果你的程序要跟别人的程序产生交互呢?尤其是当你把你在微机上运算的结果运用到计算机群上去的话。在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用big endian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的0x12345678来说,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了JAVA程序,由于JAVA采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序传给JAVA程序之前有必要进行字节序的转换工作。 

     无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。ANSI C中提供了下面四个转换字节序的宏。

 

实现代码如下:
import (
    "bytes"
    "encoding/binary"
    "fmt"
    "log"
)

func main(){
    //序列化
    var dataA uint64=6010
    var buffer bytes.Buffer
    err1 := binary.Write(&buffer, binary.BigEndian, &dataA)
    if err1!=nil{
        log.Panic(err1)
    }
    byteA:=buffer.Bytes()
    fmt.Println("序列化后:",byteA)

    //反序列化
    var dataB uint64
    var byteB []byte=byteA
    err2:=binary.Read(bytes.NewReader(byteB),binary.BigEndian,&dataB)
    if err2!=nil{
        log.Panic(err2)
    }
    fmt.Println("反序列化后:",dataB)
}

 

推荐阅读