Python: уроки, справочник и задачи

Работа с бинарными файлами в Python

Раздел: Работа с файлами в Python · Обновлено 31.10.2026

Бинарный файл в Python читается и записывается как последовательность байтов, без преобразования в текст и без учета кодировки. Из статьи вы узнаете, как открыть файл в режимах rb и wb, читать большие файлы по частям, перемещаться по ним через seek(), записывать числа в заданном формате модулем struct и сохранять объекты Python через pickle.

Работа с бинарными файлами в Python
Фото: Alchemist-hp (talk) www.pse-mendelejew.de / CC BY-SA 3.0, Wikimedia Commons
Содержание статьи
  1. Чем бинарный файл отличается от текстового
  2. Режимы открытия файла
  3. Запись и чтение байтов
    1. Чтение большого файла по частям
    2. Перемещение по файлу через seek и tell
  4. Числа и структуры: модуль struct
  5. Сохранение объектов: модуль pickle
  6. Частые вопросы
    1. Почему write() выдает TypeError: a bytes-like object is required?
    2. Как скопировать бинарный файл?
    3. Как вывести содержимое бинарного файла в шестнадцатеричном виде?
    4. Чем pickle отличается от struct?

Чем бинарный файл отличается от текстового

Любой файл на диске состоит из байтов. Разница в том, как Python их отдает. В текстовом режиме байты декодируются в строки str по указанной кодировке, а переводы строк приводятся к \n. В бинарном режиме вы получаете объект bytes ровно в том виде, в котором данные лежат на диске.

Бинарный режим нужен для изображений, аудио, архивов, PDF, исполняемых файлов и любых собственных форматов. Если открыть картинку в текстовом режиме, чтение упадет с UnicodeDecodeError или испортит данные. Работа с обычным текстом описана в статье про текстовые файлы.

Режимы открытия файла

Бинарный режим включается буквой b, которая добавляется к основному режиму функции open(). Параметр encoding в бинарном режиме указывать нельзя, это вызовет ValueError.

РежимДействиеЕсли файла нет
rbЧтениеFileNotFoundError
wbЗапись, старое содержимое стираетсяСоздается
abДозапись в конецСоздается
xbЗапись только в новый файлСоздается, а если файл есть, FileExistsError
r+bЧтение и запись без очисткиFileNotFoundError

Открывайте файлы через конструкцию with: она закроет файл даже при исключении. Общие правила открытия и закрытия разобраны в уроке открытие и закрытие файла.

Запись и чтение байтов

Метод write() принимает только байтовые объекты: bytes, bytearray или memoryview. Строку перед записью нужно закодировать методом encode(). Подробнее о байтовых строках в статье про функцию bytes.

data = bytes([0x48, 0x69, 0x00, 0xFF])

with open("sample.bin", "wb") as f:
    f.write(data)
    f.write("Привет".encode("utf-8"))

with open("sample.bin", "rb") as f:
    content = f.read()

print(len(content))   # 16
print(content[:4])    # b'Hi\x00\xff'
print(content[4:].decode("utf-8"))  # Привет

Метод read() без аргумента читает файл целиком, а read(n) возвращает не больше n байтов. Когда данные закончились, возвращается пустой объект b''. Индекс у bytes дает целое число от 0 до 255: content[3] вернет 255, а срез возвращает новый объект bytes.

Чтение большого файла по частям

Загружать в память видеофайл на несколько гигабайтов целиком нельзя. Файл читают блоками фиксированного размера в цикле. Оператор := позволяет прочитать блок и проверить его в одном выражении.

import hashlib

h = hashlib.sha256()
with open("video.mp4", "rb") as f:
    while chunk := f.read(64 * 1024):
        h.update(chunk)
print(h.hexdigest())

Так считают контрольные суммы и копируют файлы с минимальным расходом памяти. Другие приемы описаны в статье про чтение больших файлов.

Перемещение по файлу через seek и tell

Метод tell() возвращает текущую позицию в байтах, а seek(offset, whence) перемещает ее. Второй аргумент задает точку отсчета: 0 от начала, 1 от текущей позиции, 2 от конца файла.

with open("photo.png", "rb") as f:
    signature = f.read(8)
    print(signature == b"\x89PNG\r\n\x1a\n")  # True для PNG
    f.seek(0, 2)
    print("Размер:", f.tell(), "байт")

Первые байты файла называют сигнатурой: по ним определяют настоящий формат, даже если расширение изменено.

Числа и структуры: модуль struct

Если нужно записать число не как текст, а в машинном представлении, используют модуль struct. Функция pack() превращает значения в байты по строке формата, unpack() выполняет обратное действие и всегда возвращает кортеж.

import struct

# < little-endian, i - int 4 байта, d - float 8 байт, 5s - 5 байт
record = struct.pack("<id5s", 42, 3.14, b"hello")
print(len(record))  # 17

with open("record.bin", "wb") as f:
    f.write(record)

with open("record.bin", "rb") as f:
    num, value, name = struct.unpack("<id5s", f.read(17))
print(num, value, name)  # 42 3.14 b'hello'

Префикс порядка байтов важен. Символ < задает little-endian и отключает выравнивание, > задает big-endian, принятый в сетевых протоколах. Без префикса используются нативные настройки платформы с выравниванием, и размер записи может отличаться на разных компьютерах. Узнать размер записи заранее помогает struct.calcsize("<id5s").

Сохранение объектов: модуль pickle

Модуль pickle сериализует почти любой объект Python: числа, строки, списки, словари, экземпляры классов. Функция dump() записывает объект в открытый бинарный файл, load() читает его обратно.

import pickle

users = [
    ["Tom", 28, True],
    ["Alice", 23, False],
    ["Bob", 34, False],
]

with open("users.dat", "wb") as f:
    pickle.dump(users, f)

with open("users.dat", "rb") as f:
    for name, age, married in pickle.load(f):
        print(f"Имя: {name}, возраст: {age}, в браке: {married}")

В один файл можно последовательно записать несколько объектов несколькими вызовами dump. Читать их нужно столько же раз и в том же порядке, иначе на лишнем вызове load возникнет EOFError. Функции dumps() и loads() работают так же, но с объектами bytes в памяти.

Загружайте pickle только из надежных источников: при десериализации может выполниться произвольный код. Для обмена данными с другими программами лучше подходят JSON или CSV. Детали формата приведены в документации модуля pickle.

Частые вопросы

Ответы на вопросы, которые возникают при работе с бинарными файлами.

Почему write() выдает TypeError: a bytes-like object is required?

Файл открыт в бинарном режиме, а в write передана строка. Закодируйте ее: f.write(text.encode("utf-8")), или откройте файл в текстовом режиме.

Как скопировать бинарный файл?

Проще всего вызвать shutil.copyfile(src, dst). Вручную копирование делается чтением блоков из одного файла в режиме rb и записью в другой в режиме wb.

Как вывести содержимое бинарного файла в шестнадцатеричном виде?

Прочитайте байты и вызовите метод hex(): f.read(16).hex(" ") вернет строку вида "89 50 4e 47 ...". Аргумент задает разделитель между байтами.

Чем pickle отличается от struct?

struct записывает числа и байты в жестко заданном формате, понятном программам на других языках. pickle сохраняет объекты Python целиком, включая вложенные структуры, но прочитать такой файл без Python нельзя.