【发布时间】:2023-03-17 01:11:01
【问题描述】:
在最近的一个 Go 项目中,我需要读取 Python 生成的二进制数据文件,但由于填充,Go 中的 binary.Read 无法正确读取。下面是我的问题的一个最小示例。
我处理的结构体如下格式
type Index struct{
A int32
B int32
C int32
D int64
}
如您所见,结构体的大小为 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)
iiiq 格式表示结构体中有 3 个 32 位整数和 1 个 64 位整数,这与我之前定义的 Index 结构体相同。运行此代码将生成一个名为index.bin 的文件,大小为 72,等于 24 * 3。
下面是我用来阅读index.bin的Go代码:
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)
}
这是输出:
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}}
从 Python 生成的文件中读取时,显然输出是混乱的。
所以我的问题是,如何在 Go 中正确读取 python 生成的文件(带填充)?
【问题讨论】:
-
@alex 除非我严重误解了某些东西,否则这里的内存布局无关紧要,因为
binary.Read只是按顺序读取结构的元素。 -
也许这个play.golang.org/p/bCfWmKTP25 会有所帮助。
-
Python 的
structlibrary 与 C 类型兼容,而不是 Go 类型。如链接文档中所述,使用standard对齐进行独立于平台的打包。 -
抱歉,我没有正确阅读问题。但总结一下我的答案:Go struct memory layout 是由语言规范指定的。所以你可以让它成为你想要的任何东西。用额外的字段填充(如下所述)听起来是个不错的计划。