Шаг 82.
Python: сборник рецептов.
Файлы и ввод-вывод. Чтение и запись бинарных данных

    На этом шаге мы рассмотрим способы решения этой задачи.

Задача

    Вам нужно прочесть или записать бинарные данные, такие как содержимое картинок, звуковых файлов и т. п.

Решение

    Используйте функцию open() в режиме rb или wb, чтобы читать и записывать бинарные данные. Например:

#  Прочесть весь файл как одну байтовую строку 
with open('somefile.bin', 'rb') as f:
    data = f.read()

#  Записать бинарные данные в файл 
with open('somefile.bin', 'wb') as f:
    f.write(b'Hello World')

    При чтении бинарных данных важно подчеркнуть, что все получаемые данные будут в форме байтовых, а не текстовых строк. Похожим образом при записи вы должны предоставить данные в форме объектов, которые представляют данные в форме байтов (байтовые строки, объекты bytearray и т. д.).

Обсуждение

    При чтении бинарных данных тонкие сематические различия между байтовыми и текстовыми строками могут привести к проблемам. Нужно помнить, что индексирование и итерирование возвращают целочисленное байтовое значение, а не байтовые строки. Например:

>>> t = 'Hello World'
>>> t[0]
'H'
>>> for c in t:
	print(c)

	
H
e
l
l
o
 
W
o
r
l
d
>>> 
>>> # Байтовая строка 
>>> b = b'Hello World'
>>> b[0]
72
>>> for c in b:
	print(c)

	
72
101
108
108
111
32
87
111
114
108
100
>>> 

    Если вам когда-либо потребуется прочесть текст из или записать в открытый в бинарном режиме файл, убедитесь, что не забыли декодировать или закодировать его. Например:

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'))

    Менее известный аспект бинарного ввода-вывода заключается в том, что такие объекты, как массивы и структуры языка C, могут быть использованы для записи без какого-либо промежуточного преобразования в объект bytes. Например:

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])
>>>

    Однако нужно принять все меры предосторожности при использовании этого приема, поскольку он часто является платформозависимым и зависит от таких вещей, как размер слова, порядок следования байтов (big-endian или little- endian).

    На следующем шаге мы рассмотрим запись в файл, которого еще нет.




Предыдущий шаг Содержание Следующий шаг