【问题标题】:Storing 'struct' data to binary file将“结构”数据存储到二进制文件
【发布时间】:2016-03-26 02:01:22
【问题描述】:

我需要存储一个包含 4 个字段的 12 字节标头的二进制文件。它们分别是:sSamples(4 字节整数)、sSampPeriod(4 字节整数)、sSampSize(2 字节整数),最后是 sParmKind(2 字节整数)。 我正在对所需字段的变量使用“结构”。现在我已经分别定义了它们,如何将它们全部合并以存储“12 字节标头”?

sSamples        = struct.pack('i', nSamples) # 4-bytes integer
sSampPeriod     = struct.pack('i', nSampPeriod) # 4-bytes integer
sSampSize       = struct.pack('H', nSampSize) # 2-bytes integer / unsigned short
sParmKind       = struct.pack('H', 9) # 2-bytes integer / unsigned short

此外,我还有一个维度为 D (numpy.ndarray - float32) 的 npVect float 数组。如何将此向量存储在同一个二进制文件中,但在标题之后?

【问题讨论】:

  • 请注意,您可以一次打包多个值:struct.pack('Hi', foo, bar)。此外,您应该在格式字符串之前放置一个 '>' 或 '

标签: python header-files binaryfiles


【解决方案1】:

正如 Cody Brocious 所写,您可以一次打包整个标题:

header = struct.pack('<iiHH', nSamples, nSampPeriod, nSampSize, nParmKind)

他还提到了字节序,如果您想打包数据以便在具有不同架构的机器上可靠地解包,这很重要。我的格式字符串开头的 &lt; 指定“使用 little-endian 约定打包此数据”。

对于数组,您必须对其长度进行打包,以确定在再次读取时要解包多少个值。一次通话即可完成所有工作:

flattened = npVect.ravel()  # get a 1-D array of numbers
arrSize = len(flattened)
# pack header, count of numbers, and numbers, all in one call
packed = struct.pack('<iiHHi%df' % arrSize,
    nSamples, nSampPeriod, nSampSize, nParmKind, arrSize, *flattened)

根据您的数组可能有多大,您最终可能会得到一个代表二进制文件全部内容的巨大字符串,并且您可能想要寻找不需要您的 struct 的替代品将整个文件保存在内存中。

开箱:

fmt = '<iiHHi'
nSamples, nSampPeriod, nSampSize, nParmKind, arrSize = struct.unpack(fmt, packed)
# Use unpack_from to start reading after the packed header and count
flattened = struct.unpack_from('<%df' % arrSize, packed, struct.calcsize(fmt))
npVect = np.ndarray(flattened, dtype='float32').reshape(# your dimensions go here
    )

编辑:哎呀,数组格式没有那么简单 :) 不过,一般的想法是:使用任何你喜欢的方法将你的数组扁平化成一个数字列表,打包值的数量,然后打包每个值。另一方面,将数组读取为平面列表,然后在其上施加您需要的任何结构。

编辑:更改格式字符串以使用重复说明符,而不是字符串乘法。感谢 John Machin 指出。

编辑:添加了numpy 代码以在打包前展平数组并在解包后重建它。

【讨论】:

  • '&lt;iiHHi%df' % arrSize'&lt;iiHHi' + 'f' * arrSize' 更好,尤其是在数组很大的情况下。
  • +1 好点,忘了你可以在里面输入数字。但是,如果数组真的很大,由于元组解包数组,您仍将向pack 传递许多参数,并且您将从它返回一个巨大的字符串。如果性能受到足够的影响,这两者都指向寻找struct 的替代品。
  • 大家好,我遵循以下建议:arrSize = len(arr) packed = struct.pack('
  • 我的数组类型是np.ndarray of float。我需要从浮点数转换为 4 字节数组。我不完全理解打包值的数量然后打包每个值的建议。这是不是有一个 np.narray 而是我们有一个普通的 python 列表的情况,对吗?所以,如果它是一个 python 列表,我将不得不迭代向量然后调用: myElem = struct.pack('f', myFlattedArr[i]) binfile.write(myElem)?你们说的是这个吗?谢谢
  • 是的,您必须将您的 ndarray 转换为一维结构,如列表或元组。 但是不必迭代向量;这就是格式字符串中的%d*arr 的用途。如果 arr 是 17 个浮点数的列表,则 struct.pack('&lt;%df' % len(arr), *arr) 在一次调用中打包所有 n:传递给 pack 的字符串与传递 '&lt;17f' 的字符串相同(因为它的格式是使用% 运算符)并告诉 pack 期望 17 个浮点数。 *arr 中的 * 有效地将每个浮点数作为一个单独的参数传递,而不是将(列表)arr 作为一个参数传递。
【解决方案2】:

struct.pack返回一个字符串,所以你可以简单地通过字符串连接来组合字段:

header = sSamples + sSampPeriod + sSampSize + sParmKind
assert len( header ) == 12

【讨论】:

  • 您好 jhcl,感谢您的建议!要将标头存储到二进制文件中,就是这样。比如: binfile = open('myfile.dat', 'wb') binfile.write(header) 然后,如何将我的 'npVect' 变量附加到 'binfile'?
  • 这对于将值写入文件是完全正确的。我对 numpy 不熟悉,所以我会让其他人对此发表评论。
猜你喜欢
  • 2017-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 1970-01-01
  • 2019-05-14
  • 1970-01-01
相关资源
最近更新 更多