Упакуйте 4-байтовые целые числа в bytearray или массив

Я не могу понять, как это сделать, так что это может быть не так просто. Я просмотрел этот пост, этот и многие другие, но я не могу получить тип ответа Я ищу. Большинство сообщений, которые я читал, используют struct.pack или struct.pack_into, но проблема в том, что я не знаю априори размер массива, который мне нужен, и я не хотел бы создавать его для временного хранения целочисленных значений. Поэтому я подумал, что вместо этого я мог бы использовать bytearray, но я не знаю, как добавить к нему 4-байтовые целые числа.

>>> b = bytearray()
>>> for i in range(100):
...   b.append(i)
... 
>>> print(b)
bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abc')
>>> print(list(b))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
>>> import sys
>>> sys.getsizeof(b)
161

Таким образом, массив байтов не содержит 4-байтовых целых чисел (что мне и нужно). Значит, мне пришлось бы использовать какое-то заполнение нулями, чтобы получить 4-байтовые целые числа? Есть ли функция, которую я могу использовать для преобразования целого числа, переданного для добавления к типу целого числа, которое я хочу?


person aaragon    schedule 03.09.2014    source источник


Ответы (2)


Используйте тип array для хранения двоичных данных фиксированного размера, где количество значений переменная:

import array

values = array.array('I')
values.fromlist([i for i in range(100)])
bytes = values.tobytes()

Какой тип C вы выберете, зависит от архитектуры вашей системы; вам, возможно, придется выбрать один на основе атрибута array.itemsize; на моем 64-битном Mac I использует 4 байта для хранения целого числа без знака:

>>> import array
>>> values = array.array('I')
>>> values.itemsize
4
>>> values.fromlist([i for i in range(100)])
>>> len(values.tobytes())
400

Порядок байтов также зависит от машины; если вам нужны байты с прямым порядком байтов, но ваша машина использует архитектуру с прямым порядком байтов, используйте array.byteswap(), чтобы поменять порядок перед преобразованием в байты:

import sys

if sys.byteorder == 'little':
    values.byteswap()  # convert to big-endian before writing to a file
values.tofile(fileobj)
person Martijn Pieters    schedule 03.09.2014
comment
Кажется, однако, что для его построения нужно априори знать размер массива, не так ли? - person aaragon; 03.09.2014
comment
@aaragon: нет, не знаешь. Массивы содержат произвольное количество элементов. Вам нужно только знать размер целевого байта. - person Martijn Pieters; 03.09.2014
comment
Отлично, я только что видел метод append для класса массива. Должен ли я использовать len(values) * values.itemsize для сохранения общего размера, или есть ярлык? - person aaragon; 03.09.2014
comment
Нет ярлыка; умножение длины на размер элемента - вот как я это сделаю. - person Martijn Pieters; 03.09.2014
comment
Просто быстрый вопрос о внутренностях массива. Я не знаю, как это реализовано внутри, но я предполагаю, что если у него есть метод append, это похоже на двойной список лайков, не так ли? Это означает, что вставка элемента в позицию 0 после формирования массива может быть выполнена без манипулирования остальной частью массива, верно? - person aaragon; 03.09.2014
comment
@aaragon: это не двусвязный список; это динамически увеличивающийся массив. - person Martijn Pieters; 03.09.2014
comment
Так что вставлять элементы по одному очень дорого :/ - person aaragon; 03.09.2014
comment
См. array источник; например массивы объектов Python list перераспределяются и изменяются по мере необходимости. Вставка значений в начале действительно потребует вызова memmove для перемещения всего после вставки вверх. - person Martijn Pieters; 03.09.2014
comment
@aaragon: в качестве альтернативы рассмотрите возможность реверсирования, добавления и реверсирования. - person Martijn Pieters; 03.09.2014

Это то, что вы хотите?

>>> import struct
>>> b = bytearray()
>>> b = b""
>>> for i in range(100):
...     b += struct.pack("<i", i)
... 
>>> len(b)
400
>>> b
b'\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\t\x00\x00\x00\n\x00\x00\x00\x0b\x00\x00\x00\x0c\x00\x00\x00\r\x00\x00\x00\x0e\x00\x00\x00\x0f\x00\x00\x00\x10\x00\x00\x00\x11\x00\x00\x00\x12\x00\x00\x00\x13\x00\x00\x00\x14\x00\x00\x00\x15\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\x18\x00\x00\x00\x19\x00\x00\x00\x1a\x00\x00\x00\x1b\x00\x00\x00\x1c\x00\x00\x00\x1d\x00\x00\x00\x1e\x00\x00\x00\x1f\x00\x00\x00 \x00\x00\x00!\x00\x00\x00"\x00\x00\x00#\x00\x00\x00$\x00\x00\x00%\x00\x00\x00&\x00\x00\x00\'\x00\x00\x00(\x00\x00\x00)\x00\x00\x00*\x00\x00\x00+\x00\x00\x00,\x00\x00\x00-\x00\x00\x00.\x00\x00\x00/\x00\x00\x000\x00\x00\x001\x00\x00\x002\x00\x00\x003\x00\x00\x004\x00\x00\x005\x00\x00\x006\x00\x00\x007\x00\x00\x008\x00\x00\x009\x00\x00\x00:\x00\x00\x00;\x00\x00\x00<\x00\x00\x00=\x00\x00\x00>\x00\x00\x00?\x00\x00\x00@\x00\x00\x00A\x00\x00\x00B\x00\x00\x00C\x00\x00\x00D\x00\x00\x00E\x00\x00\x00F\x00\x00\x00G\x00\x00\x00H\x00\x00\x00I\x00\x00\x00J\x00\x00\x00K\x00\x00\x00L\x00\x00\x00M\x00\x00\x00N\x00\x00\x00O\x00\x00\x00P\x00\x00\x00Q\x00\x00\x00R\x00\x00\x00S\x00\x00\x00T\x00\x00\x00U\x00\x00\x00V\x00\x00\x00W\x00\x00\x00X\x00\x00\x00Y\x00\x00\x00Z\x00\x00\x00[\x00\x00\x00\\\x00\x00\x00]\x00\x00\x00^\x00\x00\x00_\x00\x00\x00`\x00\x00\x00a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00'

Дополнительные сведения о кодах упаковки структур см. на странице https://docs.python.org/3.4/library/struct.html. В моем коде используется i для int и < для прямого порядка байтов.

person matsjoyce    schedule 03.09.2014