Python. Модуль struct. Работа с бинарными файлами




Модуль struct. Работа с бинарными файлами. Примеры сохранения/чтения упакованных двоичных данных


Содержание


Поиск на других ресурсах:

1. Применение средств модуля struct для работы с файлами

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

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

  • во время записи данных в файл, они предварительно упаковываются с помощью методов pack() или pack_into();
  • при считывании предварительно записанных упакованных данных, они распаковываются методами unpack() или unpack_into().

 

2. Примеры использования средств модуля struct
2.1. Пример записи/чтения разнотипных данных в файл

В примере сначала записываются, а затем читаются данные, которые размещены в списке. Типы данных отличаются: float, bool, char[].

# Бинарные файлы. Запись/чтение списка разнотипных данных.
# Использование возможностей модуля struct.

# 1. Подключить модуль struct
import struct

# 2. Заданный список разнотипных данных:
#   - 1.5 - тип float, в struct обозначен 'f'
#   - True - тип bool, в struct обозначен '?'
#   - 'abc def' - тип char[], в struct обозначен 's'
L = [1.5, True, 'abc def']

# 3. Запись списка L в файл 'myfile4.bin'
# 3.1. Открыть файл для записи
f = open('myfile4.bin', 'wb')

# 3.2. Записать список в упакованном формате.
#     Для упаковки данных используется метод pack()
#     Расшифровка строки '>f?7s':
#     - '>' - обратный порядок байт (старшие байты следуют последними);
#     - 'f' - тип float;
#     - '?' - тип bool;
#     - '7s' - тип char[] размером 7 символов.
d = struct.pack('>f?7s', L[0], L[1], L[2].encode())

# 3.3. Записать упакованные данные d в файл
f.write(d)

# 3.4. Закрыть файл
f.close();

# 4. Прочитать список из бинарного файла 'myfile4.bin'
# 4.1. Открыть файл для чтения
f = open('myfile4.bin', 'rb')

# 4.2. Прочитать данные из файла
d = f.read()

# 4.3. Распаковать данные с помощью метода unpack().
#     Данные распаковываются в виде кортежа.
T = struct.unpack('>f?7s', d)

# 4.4. Конвертировать кортеж T в список L2
L2 = list(T)

# 4.5. Конвертировать строку L2[2] в тип str
L2[2] = L2[2].decode()

# 4.6. Вывести список
print("L2 = ", L2) # L2 =   [1.5, True, 'abc def']

# 4.7. Закрыть файл
f.close();

Результат работы программы

L2 = [1.5, True, 'abc def']

 



2.2. Пример записи/чтения списка, содержащего целые числа

В примере продемонстрирована запись списка в файл и чтение списка из файла. При чтении списка из файла размер записанного ранее списка заведомо неизвестен.

При записи списка происходит поэлементная запись на основе строки формата ‘>i’. В случае чтения, сначала читается количество элементов, а, затем уже читается весь список за один раз с помощью строки

T = struct.unpack('>ni', d)

где

  • ‘>ni’ – строка формата, в котором n – количество записанных элементов;
  • d – двоичный объект;
  • T – кортеж чисел, полученных при распаковывании объекта d.

 

# Бинарные файлы. Модуль struct.

# Пример записи/чтения списка целых чисел
# 1. Подключить модуль struct
import struct

# 2. Заданный список
L = [ 2, 4, 6, 8, 10 ]

# 3. Запись списка в файл
# 3.1. Открыть файл для записи
f = open('myfile9.bin', 'wb')

# 3.2. Записать список в файл поэлементно
# 3.2.1. Получить упакованный объект данных на основе списка s
d = struct.pack('>i', len(L))

# 3.2.2. Записать объект d в файл
f.write(d)

# 3.2.3. Записать элементы по одному - так тоже можно
for item in L:
    d = struct.pack('>i', item)
    f.write(d)

# 3.3. Закрыть файл
f.close()

# ---------------------------------------------
# 4. Чтение списка из файла
# 4.1. Открыть файл для чтения
f = open('myfile9.bin', 'rb')

# 4.2. Считать количество элементов списка - первое число в файле,
#      считываются первые 4 байта - размер типа int
d = f.read(4) # d - двоичный объект
count = struct.unpack('>i', d)[0]

# 4.3. Считать весь список в двоичный объект d
d = f.read() # чтение происходит из текущей позиции до конца файла

# 4.4. Сформировать строку формата для чтения всех чисел за один раз
#     (числа можно также читать по одному в цикле)
s = '>' + str(count) + 'i'

# 4.5. Получить кортеж из чисел на основе строки формата
T = struct.unpack(s, d)

# 4.6. Конвертировать кортеж в список
L2 = list(T)

# 4.7. Вывести список для контроля
print("L2 = ", L2)

# 4.8. Закрыть файл
f.close()

Результат работы программы

L2 = [2, 4, 6, 8, 10]

 

2.3. Пример записи/чтения кортежа, содержащего строки

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

# Бинарные файлы. Модуль struct.

# Пример записи/чтения кортежа строк.
# 1. Подключить модуль struct
import struct

# 2. Заданный кортеж строк, которые нужно записать в файл.
T = ( 'abc', 'abcd', 'def', 'ghi jkl')

# 3. Запись в файл кортежа T
# 3.1. Открыть файл для записи в бинарном режиме
f = open('myfile10.bin', 'wb')

# 3.2. Записать количество элементов в кортеже
count = len(T)
d = struct.pack('>i', count) # получить упакованные данные
f.write(d) # записать упакованные данные

# 3.3. Записать каждую строку кортежа в цикле.
#      Поскольку каждая строка имеет разную длину,
#      то эту длину нужно также записывать в файл.
for item in T: # цикл обхода элементов кортежа
    # взять длину строки item
    length = len(item)

    # упаковать длину строки length
    d = struct.pack('>i', length)

    # записать в файл
    f.write(d)

    # упаковать строку item: '>ns' - означает char[n]
    bt_item = item.encode() # конвертировать str=>bytes
    d = struct.pack('>' + str(length) + 's', bt_item)

    # записать в файл
    f.write(d)

# 3.4. Закрыть файл
f.close()

# ------------------------------------------------------
# 4. Чтение записанного кортежа из файла
# 4.1. Открыть файл для чтения в бинарном режиме
f = open('myfile10.bin', 'rb')

# 4.2. Считать количество элементов (строк) в файле
d = f.read(4) # Считать первые 4 байта - размер типа int, d - упакованные данные
count = struct.unpack('>i', d)[0] # count - количество элементов

# 4.3.Сформировать пустой кортеж-результат
T2 = ()

# 4.4. Цикл чтения строк
i = 0
while i<count:
    # считать длину строки
    d = f.read(4)
    length = struct.unpack('>i', d)[0] # length - длина строки

    # сформировать строку формата
    sf = '>' + str(length) + 's'

    # считать length байт из файла в объект d
    d = f.read(length)

    # распаковать строку согласно строке sf
    sb = struct.unpack(sf, d)[0] # sb - строка типа bytes

    # конвертировать bytes=>str
    s = sb.decode()

    # Добавить строку к кортежу
    T2 = T2 + (s,)

    i = i+1

# 4.5. Вывести кортеж T2 для контроля
print("T2 = ", T2)

# 4.6. Закрыть файл
f.close()

Результат работы программы

T2 = ('abc', 'abcd', 'def', 'ghi jkl')

 

2.4. Пример записи/чтения словаря в котором пара ключ:значение имеет тип int:str

 

# Бинарные файлы. Модуль struct.
# Пример записи/чтения словаря

# 1. Подключить модуль struct
import struct

# 2. Исходный словарь
D = { 1:'Sunday', 2:'Monday', 3:'Tuesday', 4:'Wednesday',
      5:'Thursday', 6:'Friday', 7:'Saturday' }

# 3. Запись в файл кортежа T
# 3.1. Открыть файл для записи в бинарном режиме
f = open('myfile11.bin', 'wb')

# 3.2. Записать количество элементов в словаре
count = len(D)
d = struct.pack('>i', count) # получить упакованные данные
f.write(d) # записать упакованные данные

# 3.3. Записать каждую строку словаря в цикле.
#     Поскольку каждая строка может иметь разную длину,
#     то эту длину нужно также записывать в файл.
for key in D: # цикл обхода элементов словаря
    # записать ключ - целое число
    dd = struct.pack('>i', key)
    f.write(dd)

    # записать строку по ключу
    # взять длину строки item
    length = len(D[key])

    # упаковать длину строки length
    dd = struct.pack('>i', length)

    # записать в файл длину
    f.write(dd)

    # упаковать строку D[key]: '>ns' - означает char[n]
    bt_item = D[key].encode() # конвертировать str=>bytes
    dd = struct.pack('>' + str(length) + 's', bt_item)

    # записать в файл
    f.write(dd)

# 3.4. Закрыть файл
f.close()

# ------------------------------------------------------
# 4. Чтение записанного кортежа из файла
# 4.1. Открыть файл для чтения в двоичном режиме
f = open('myfile11.bin', 'rb')

# 4.2. Считать количество элементов (строк) в файле
dd = f.read(4) # Считать первые 4 байта - размер типа int, d - упакованные данные
count = struct.unpack('>i', dd)[0] # count - количество элементов в словаре

# 4.3.Сформировать пустой словарь-результат
D2 = dict()

# 4.4. Цикл чтения строк
i = 0
while i<count:
    # 4.4.1. Считать ключ key - целое число размером 4 байта
    dkey = f.read(4)
    key = struct.unpack('>i', dkey)[0] # распаковать данные

    # 4.4.2. Прочитать количество символов в строке
    dlength = f.read(4) # 4 - целое число типа int
    length = struct.unpack('>i', dlength)[0]

    # 4.4.3. Прочитать строку, предварительно нужно сформировать
    # строку формата sf
    sf = '>' + str(length) + 's'
    ds = f.read(length) # считать из файла length байт
    sb = struct.unpack(sf, ds)[0] # распаковать строку
    value = sb.decode()

    # 4.4.4. Добавить пару key:value к словарю D2
    D2[key] = value

    i = i+1

# 4.5. Вывести словарь D2 для контроля
print("D2 = ", D2)

# 4.6. Закрыть файл
f.close()

Результат работы программы

D2 = {1: 'Sunday', 2: 'Monday', 3: 'Tuesday', 4: 'Wednesday', 5: 'Thursday', 6: 'Friday', 7: 'Saturday'}

 


Связанные темы