binary.Read不按预期处理struct padding

Der*_*ang 2 struct padding go

在最近的Go项目中,我需要读取由Python生成的二进制数据文件,但由于填充,binary.ReadGo中没有正确读取它.以下是我的问题的最小例子.

我处理的结构如果是以下格式

type Index struct{
    A int32
    B int32
    C int32
    D int64
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,结构的大小是4 + 4 + 4 + 8 = 20,但Python为对齐添加了额外的4个字节.所以大小实际上是24.

下面是我用来编写这个结构的可运行的Python代码:

#!/usr/bin/env python
# encoding=utf8

import struct

if __name__ == '__main__':
    data = range(1, 13)
    format = 'iiiq' * 3
    content = struct.pack(format, *data)
    with open('index.bin', 'wb') as f:
        f.write(content)
Run Code Online (Sandbox Code Playgroud)

iiiq格式是指有3个32位的整数,并且在结构,其是与相同的一个64位的整数Index余前面定义结构.运行此代码将生成一个名为index.bin72 的文件,该文件等于24*3.

以下是我用来阅读的Go代码index.bin:

package main

import (
        "encoding/binary"
        "fmt"
        "os"
        "io"
        "unsafe"
)

type Index struct {
        A int32
        B int32
        C int32
        D int64
}

func main() {
        indexSize := unsafe.Sizeof(Index{})
        fp, _ := os.Open("index.bin")
        defer fp.Close()
        info, _ := fp.Stat()
        fileSize := info.Size()
        entryCnt := fileSize / int64(indexSize)
        fmt.Printf("entry cnt: %d\n", entryCnt)

        readSlice := make([]Index, entryCnt)
        reader := io.Reader(fp)
        _ = binary.Read(reader, binary.LittleEndian, &readSlice)
        fmt.Printf("After read:\n%#v\n", readSlice)
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

entry cnt: 3
After read:
[]main.Index{main.Index{A:1, B:2, C:3, D:17179869184}, main.Index{A:0, B:5, C:6, D:7}, main.Index{A:8, B:0, C:9, D:47244640266}}
Run Code Online (Sandbox Code Playgroud)

显然,当从Python生成的文件中读取时,输出会混乱.

所以我的问题是,如何在Go中正确读取python生成的文件(带填充)?

Dar*_*tle 7

你可以填充你的Go结构来匹配:

type Index struct {
    A int32
    B int32
    C int32
    _ int32
    D int64
}
Run Code Online (Sandbox Code Playgroud)

哪个产生:

[]main.Index{main.Index{A:1, B:2, C:3, _:0, D:4}, main.Index{A:5, B:6, C:7, _:0, D:8}, main.Index{A:9, B:10, C:11, _:0, D:12}}
Run Code Online (Sandbox Code Playgroud)

binary.Read知道跳过这个_领域:

读入结构时,将跳过具有空白(_)字段名称的字段的字段数据; 即,空白字段名称可用于填充.

(因此,0_不是因为文件中的填充设置为零,而是因为struct字段已初始化为0且从未更改过,并且文件中的填充被跳过而不是读取.)