5.4 读写字节数�¶

问题¶

你想读写二进制文件,比如图片,声音文件等等。

解决方案¶

使用模�为 rb 或 wb 的 open() 函数�读�或写入二进制数�。比如:

# Read the entire file as a single byte string
with open('somefile.bin', 'rb') as f:
    data = f.read()

# Write binary data to a file
with open('somefile.bin', 'wb') as f:
    f.write(b'Hello World')

在读�二进制数�时,需�指明的是所有返回的数�都是字节字符串格�的,而�是文本字符串。 类似的,在写入的时候,必须���数是以字节形�对外暴露数�的对象(比如字节字符串,字节数组对象等)。

讨论¶

在读�二进制数�的时候,字节字符串和文本字符串的语义差异�能会导致一个潜在的陷阱。 特别需�注�的是,索引和迭代动作返回的是字节的值而�是字节字符串。比如:

>>> # Text string
>>> t = 'Hello World'
>>> t[0]
'H'
>>> for c in t:
...     print(c)
...
H
e
l
l
o
...
>>> # Byte string
>>> b = b'Hello World'
>>> b[0]
72
>>> for c in b:
...     print(c)
...
72
101
108
108
111
...
>>>

如果你想从二进制模�的文件中读�或写入文本数�,必须确��进行解�和编��作。比如:

with open('somefile.bin', 'rb') as f:
    data = f.read(16)
    text = data.decode('utf-8')

with open('somefile.bin', 'wb') as f:
    text = 'Hello World'
    f.write(text.encode('utf-8'))

二进制I/O还有一个鲜为人知的特性就是数组和C结构体类型能直接被写入,而�需�中间转�为自己对象。比如:

import array
nums = array.array('i', [1, 2, 3, 4])
with open('data.bin','wb') as f:
    f.write(nums)

这个适用于任何实现了被称之为�缓冲接��的对象,这�对象会直接暴露其底层的内存缓冲区给能处�它的�作。 二进制数�的写入就是这类�作之一。

很多对象还�许通过使用文件对象的 readinto() 方法直接读�二进制数�到其底层的内存中去。比如:

>>> import array
>>> a = array.array('i', [0, 0, 0, 0, 0, 0, 0, 0])
>>> with open('data.bin', 'rb') as f:
...     f.readinto(a)
...
16
>>> a
array('i', [1, 2, 3, 4, 0, 0, 0, 0])
>>>

但是使用这�技术的时候需�格外�心,因为它通常具有平�相关性,并且�能会�赖字长和字节顺�(高�优先和低�优先)。 �以查看5.9�节中�外一个读�二进制数�到�修改缓冲区的例�。