在Python中将二进制数据写入文件

12

我想以二进制方式将数据(文本、浮点数据)写入文件,以便稍后由另一个程序读取。问题是这个程序(使用Fort95编写)非常特殊;每个字节都必须恰好处于正确的位置,才能正确地读取文件。我尝试过使用Bytes对象和.encode()写入,但没有取得太大的成功(从文件大小可以看出它正在写入额外的数据字节)。一些我尝试过的代码:

mgcnmbr='42'
bts=bytes(mgcnmbr)
test_file=open(PATH_HERE/test_file.dat','ab')
test_file.write(bts)
test_file.close()

我也尝试过:

mgcnmbr='42'
bts=mgcnmbr.encode(utf_32_le)
test_file=open(PATH_HERE/test_file.dat','ab')
test_file.write(bts)
test_file.close()

为了澄清,我需要的是整数值42,用4个字节的二进制表示。接下来,我会用4个字节的二进制书写数字1和0。这时,我应该正好有12个字节。每个字节都是一个4个字节的有符号整数,以二进制形式书写。我对Python还不太熟悉,似乎无法使其正常工作。有什么建议吗?类似于这个?我需要完全控制每个整数(以及稍后的4个字节浮点数)占用的字节数。

谢谢


查阅标准库中的 struct.pack - Wooble
http://stackoverflow.com/questions/29834047/write-binary-string-in-binary-file-python-3-4/29855780#29855780 - Green Carpet
3个回答

23

你需要struct模块。

import struct

fout = open('test.dat', 'wb')

fout.write(struct.pack('>i', 42))
fout.write(struct.pack('>f', 2.71828182846))

fout.close()

struct.pack中的第一个参数是格式字符串。

格式字符串中的第一个字符决定了数据的字节顺序或endianness(最高有效字节或最低有效字节是先存储,即大端序还是小端序)。字节顺序因系统而异。如果“>”无法使用,请尝试“<”。

格式字符串中的第二个字符是数据类型。毫不意外,“i”代表整数,“f”代表浮点数。类型决定了字节数。例如,短整型或“h”的长度为两个字节。还有无符号类型的代码。例如,“H”对应于无符号短整型。

struct.pack中的第二个参数当然是要打包到字节对象中的值。

这里是我告诉你我撒了几个谎的部分。首先,我说字节数取决于类型,但这只是部分正确的。给定类型的大小在技术上是取决于平台的,因为C/C++标准(struct模块基于此)仅指定了最小尺寸。这导致我撒的第二个谎言。格式字符串中的第一个字符还编码了是否使用标准(最小)字节数或本机(平台相关)字节数。 (">"和"<"都保证使用标准的最小字节数,在整数"i"或浮点数"f"的情况下实际上是四个字节。)它还编码了数据的对齐方式struct模块文档中有关于格式字符串参数的表格。
你也可以将多个基元打包到单个字节对象中,并实现相同的结果。
import struct

fout = open('test.dat', 'wb')

fout.write(struct.pack('>if', 42, 2.71828182846))

fout.close()

当然,你可以使用struct.unpack解析二进制数据。

2
那是正确的做法。只有一个额外的提示:使用with语句可以避免忘记close - xtofl
注意,将符号“>”用于struck.pack格式链只适用于大端系统,如Motorola 68000或PowerPC G5,最好使用“@”符号,这将创建本机格式(大端或小端)的文件,但请注意,此文件无法在其他平台上移植。 - Juanma Font
这个答案可以通过解释为什么使用结构模块比其他方式更好(例如直接编写字节)来改进。 - Jacob Lee

0
假设你想要使用小端序,你可以像这样写一个四字节二进制数来表示42。
test_file=open(PATH_HERE/test_file.dat','ab')
test_file.write(b'\xA2\0\0\0')
test_file.close()

A2 是十六进制的 42,而字节 '\xA2\0\0\0' 使得第一个字节等于 42,后面跟着三个空字节。这段代码写入的字节是:42、0、0、0。

你的代码将写入表示字符 '4' 在 UTF 32 中的字节和表示数字 2 在 UTF 32 中的字节。这意味着它将写入字节:52、0、0、0、50、0、0、0,因为每个字符在 UTF 32 编码时占用四个字节。

此外,拥有一个十六进制编辑器进行调试可能对你有用,这样你就可以看到你的程序输出的字节,而不仅仅是大小。


是的,我理解正在发生的事情是它将每个字符作为UTF32中的4字节值编写,这就是为什么在使用小端时会得到8字节的原因。但是,该程序主要用作转换器,它从文件中读取数据并以正确的二进制形式传输到另一个文件。这些文件非常庞大,有数十万行和值被写入其中。因此,我不能为每个值输入十六进制形式。 - Schafer
chr(y&0xFF) + chr((y>>8)&0xFF) + chr((y>>(8*2))&0xFF) + chr((y>>(8*3))&0xFF) 可以用于将四字节整数 y 转换为字符串。它通过将数字向下移位并逐个输入字节来完成。我不知道如何处理浮点数。 -- 如果您知道需要哪些字节并且使用 Python3,则可以使用 bytes([<1st byte>, <2nd byte>, <3rd byte>, <4th byte>])。将<>替换为您想要的字节即可。 - Algorithmic Canary

-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接