Python如何写入二进制文件?


128

我有一个字节列表作为整数,这就像

[120, 3, 255, 0, 100]

如何将该列表作为二进制文件写入文件?

这行得通吗?

newFileBytes = [123, 3, 255, 0, 100]
# make file
newFile = open("filename.txt", "wb")
# write to file
newFile.write(newFileBytes)

60
您问“这项工作吗?”。你试过了吗?
StephenTG

1
应该是TypeError: argument 1 must be string or buffer, not list
anatoly techtonik '16

Answers:


128

这正是bytearray用于:

newFileByteArray = bytearray(newFileBytes)
newFile.write(newFileByteArray)

如果您使用的是Python 3.x,则可以bytes改用(也许应该这样做,因为它可以更好地表明您的意图)。但是在Python 2.x中,这bytes是行不通的,因为它只是的别名str。像往常一样,使用交互式解释器进行显示比使用文本进行解释要容易,所以让我这样做。

Python 3.x:

>>> bytearray(newFileBytes)
bytearray(b'{\x03\xff\x00d')
>>> bytes(newFileBytes)
b'{\x03\xff\x00d'

Python 2.x:

>>> bytearray(newFileBytes)
bytearray(b'{\x03\xff\x00d')
>>> bytes(newFileBytes)
'[123, 3, 255, 0, 100]'

1
很好地使用内置类型。只需注意字节数组是在2.6中添加的,如果要支持旧系统,应避免使用它。
2013年

7
@Perkins:当然,如果需要使用2.3,则应避免使用生成器表达式,请谨慎使用两者str.encodestruct.pack如果需要使用2.2。但是2.6已经发布了5年。所有这三个Ubuntu LTS仍受支持,所有三个OS X版本均受支持,CentOS / RHEL的先前主要版本等都是内置的。如果需要支持2.5或2.1或1.6或其他任何功能,则可能知道…
abarnert

4
在Windows上的Python 2中,我发现如果在打开文件时未传递“ b”标志,则编写一个bytearraystill会转换\n\r\n,从而使它对于二进制数据不令人满意。
feersum 2014年

6
@feersum:当然;这就是2.x中二进制与文本模式的含义。字节来自哪种类型都没有关系。(当然,在3.x中,二进制vs.文本模式意味着您编写字节与unicode,并且此\r\n功能是文本通用换行选项的一部分。)
abarnert 2014年

我不确定bytearray()是写文件的好选择。您需要将大小限制为可管理的块。否则,一旦文件大小过高,就会用完内存。
mckenzm

30

使用struct.pack的整数值转换成二进制字节,然后写入字节。例如

newFile.write(struct.pack('5B', *newFileBytes))

但是,我永远不会给二进制文件.txt扩展名。

此方法的好处是它也适用于其他类型,例如,如果任何值大于255,都可以使用'5i'该格式代替获取完整的32位整数。


如果您有某种方式可以知道正在写入的数据都在可打印的ascii范围内,则.txt很好。但是,在这种情况下,我认为您是正确的,因为示例数据包含不可打印的字符。
2013年

@Perkins我没有假设值在ASCII范围内甚至小于256。即使它们是.txt文件,也应该为那些永远不会应用于二进制数据的人保留。
Mark Ransom

1
没错,如果要写入值大于255的数据,struct.pack也是可行的方法,因为bytearray和chr都不能处理较大的整数值。
2013年

1
@MarkRansom:好的,对于“我有一些任意但固定大小的整数列表,如何将它们写入二进制文件?”这个更普遍的问题,这仍然绝对是一个好的解决方案。我可以看到人们正在搜索该问题并找到了这个问题……
abarnert 2013年

1
struct.pack是更好的答案;它比仅创建字节数组要灵活得多。
赛斯

12

要将<256的整数转换为二进制,请使用chr函数。因此,您正在考虑执行以下操作。

newFileBytes=[123,3,255,0,100]
newfile=open(path,'wb')
newfile.write((''.join(chr(i) for i in newFileBytes)).encode('charmap'))

1
您的意思必须是<128。如python3所抱怨:UnicodeEncodeError:'ascii'编解码器无法在位置0编码字符'\ x89':序号不在range(128)
合法

2
不,我的意思是<256,但是编码应该是charmap而不是ascii,并且可以在python2和python3中使用。该ascii编码只能在python2。
珀金斯

9

从Python 3.2+开始,您还可以使用本to_bytes机int方法完成此操作:

newFileBytes = [123, 3, 255, 0, 100]
# make file
newFile = open("filename.txt", "wb")
# write to file
for byte in newFileBytes:
    newFile.write(byte.to_bytes(1, byteorder='big'))

也就是说,to_bytes在这种情况下,每次调用都会创建一个长度为1的字符串,其字符以大端顺序排列(对于长度为1的字符串而言,这是微不足道的),它表示整数值byte。您还可以将最后两行缩短为一行:

newFile.write(''.join([byte.to_bytes(1, byteorder='big') for byte in newFileBytes]))

8

您可以使用以下使用Python 3语法的代码示例:

from struct import pack
with open("foo.bin", "wb") as file:
  file.write(pack("<IIIII", *bytearray([120, 3, 255, 0, 100])))

这是外壳一线:

python -c $'from struct import pack\nwith open("foo.bin", "wb") as file: file.write(pack("<IIIII", *bytearray([120, 3, 255, 0, 100])))'

1

像这样使用泡菜:导入泡菜

您的代码如下所示:

import pickle
mybytes = [120, 3, 255, 0, 100]
with open("bytesfile", "wb") as mypicklefile:
    pickle.dump(mybytes, mypicklefile)

要读回数据,请使用pickle.load方法


3
这不会产生5个字节长的二进制文件,其中唯一的内容是120、3、255、0、100。在封闭的系统中,这可能是可以接受的。
parvus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.