Python як записати у двійковий файл?


128

У мене є список байтів як цілих чисел, що є чимось подібним

[120, 3, 255, 0, 100]

Як я можу записати цей список у файл як двійковий?

Це би спрацювало?

newFileBytes = [123, 3, 255, 0, 100]
# make file
newFile = open("filename.txt", "wb")
# write to file
newFile.write(newFileBytes)

60
Ви запитуєте "Чи це працювало?". Ви пробували?
StephenTG

1
Повинно бути TypeError: argument 1 must be string or buffer, not list.
anatoly techtonik

Відповіді:


128

Це саме те, що bytearrayдля:

newFileByteArray = bytearray(newFileBytes)
newFile.write(newFileByteArray)

Якщо ви використовуєте Python 3.x, ви можете використовувати bytesнатомість (і, мабуть, варто, оскільки це краще сигналізує про ваш намір). Але в Python 2.x це не спрацює, оскільки bytesце лише псевдонім для str. Як завжди, показувати інтерактивного перекладача простіше, ніж пояснити текстом, тому дозвольте мені це зробити.

Python 3.x:

>>> bytearray(newFileBytes)
bytearray(b'{\x03\xff\x00d')
>>> bytes(newFileBytes)
b'{\x03\xff\x00d'

Python 2.x:

>>> bytearray(newFileBytes)
bytearray(b'{\x03\xff\x00d')
>>> bytes(newFileBytes)
'[123, 3, 255, 0, 100]'

1
Гарне використання вбудованих типів. Зауважте лише, що байт-масив додано в 2.6, якщо ви хочете підтримувати застарілі системи, цього слід уникати.
Перкінс

7
@Perkins: Звичайно, і вам слід уникати генераторних виразів, якщо вам потрібно працювати над 2.3, будьте обережні з обома, str.encodeі struct.packякщо вам потрібно працювати над 2.2. Але 2,6 вже 5 років; усі три Ubuntu LTS все ще підтримуються, всі три версії OS X, що підтримуються, попередня основна версія CentOS / RHEL і т. д., усі вбудовані в неї. Якщо вам потрібно підтримувати 2.5 або 2.1 або 1.6 або будь-яку іншу, ви, ймовірно, знаю…
abarnert

4
За допомогою Python 2 у Windows я виявив, що запис bytearrayнерухомого файлу перетворюється \nна \r\n, що робить його незадовільним для двійкових даних, якщо прапор "b" не буде передано під час відкриття файлу.
feersum

6
@feersum: Звичайно; ось що означає бінарний та текстовий режим у 2.x. Не має значення, від якого типу байти беруться. (У 3.x, звичайно, бінарний та текстовий режим означає, що ви пишете байти проти unicode, а \r\nфункція є частиною універсальних параметрів нових рядків для тексту.)
abarnert

Я не впевнений, що bytearray () - хороший вибір для написання файлів. Вам потрібно буде обмежити розмір керованими шматками. Інакше, як тільки ваші розміри файлів стануть занадто високими, у вас не вистачить пам'яті.
mckenzm

31

Використовуйте struct.packдля перетворення цілих значень у двійкові байти, а потім записуйте байти. Напр

newFile.write(struct.pack('5B', *newFileBytes))

Однак я ніколи не давав бинарного файлу .txtрозширення.

Перевага цього методу полягає в тому, що він працює і для інших типів, наприклад, якщо будь-яке значення перевищує 255, ви можете використовувати '5i'для формату замість цього, щоб отримати повні 32-бітні цілі числа.


.txt чудово, якщо у вас є якийсь спосіб дізнатися, що дані, які ви записуєте, потрапляють у діапазон ascii для друку. Однак ви вірні, я думаю, що в цьому випадку, оскільки приклад даних включає недруковані символи.
Перкінс

@Perkins Я не припускав, що значення в діапазоні ASCII будуть навіть меншими, ніж 256. Навіть якщо вони є, .txt-файли повинні бути зарезервовані для тих, хто має сенс для людини, які ніколи не стосуються двійкових даних.
Марк Рансом

1
Ви маєте рацію, struct.pack - це також шлях, якщо ви збираєтеся записувати дані зі значеннями вище 255, оскільки ні байт-масив, ні chr не можуть обробити більші цілі значення.
Перкінс

1
@MarkRansom: Ну, це, безумовно, хороше рішення більш загальної проблеми "У мене є список цілих чисел якогось довільного, але фіксованого розміру, як я можу записати їх у двійковий файл?" і я бачу людей, які шукають це питання і знаходять це…
abarnert

1
Stru.pack - краща відповідь; це набагато гнучкіше, ніж просто створити байт-масив.
Сет

12

Щоб перетворити з цілих чисел <256 в двійкові, скористайтеся chrфункцією. Отже, ви дивитесь на те, щоб зробити наступне.

newFileBytes=[123,3,255,0,100]
newfile=open(path,'wb')
newfile.write((''.join(chr(i) for i in newFileBytes)).encode('charmap'))

1
Ви повинні мати на увазі <128. Як скаржиться python3: UnicodeEncodeError: 'ascii' кодек не може кодувати символ '\ x89' у позиції 0: порядковий не в діапазоні (128)
відміряти

2
Ні, я маю на увазі <256, але кодування має бути, charmapа не ascii, і працює як в python2, так і в python3. asciiКодування працює тільки в python2.
Перкінс

9

Як і в Python 3.2+, ви також можете це досягти, використовуючи to_bytesнативний метод int:

newFileBytes = [123, 3, 255, 0, 100]
# make file
newFile = open("filename.txt", "wb")
# write to file
for byte in newFileBytes:
    newFile.write(byte.to_bytes(1, byteorder='big'))

Тобто кожен виклик to_bytesв цьому випадку створює рядок довжиною 1, його символи розташовані в порядку великого ендіану (що є тривіальним для рядків довжиною-1), що представляє ціле число byte. Ви також можете скоротити останні два рядки в один:

newFile.write(''.join([byte.to_bytes(1, byteorder='big') for byte in newFileBytes]))

8

Ви можете використовувати наступний приклад коду, використовуючи синтаксис Python 3:

from struct import pack
with open("foo.bin", "wb") as file:
  file.write(pack("<IIIII", *bytearray([120, 3, 255, 0, 100])))

Ось оболонка з одним вкладишем:

python -c $'from struct import pack\nwith open("foo.bin", "wb") as file: file.write(pack("<IIIII", *bytearray([120, 3, 255, 0, 100])))'

1

Використовуйте соління, як це: імпортувати соління

Ваш код виглядатиме так:

import pickle
mybytes = [120, 3, 255, 0, 100]
with open("bytesfile", "wb") as mypicklefile:
    pickle.dump(mybytes, mypicklefile)

Щоб прочитати дані назад, використовуйте метод pickle.load


3
Це не створює двійковий файл довжиною 5 байтів, де єдиний вміст становить 120, 3, 255, 0, 100. Однак у закритій системі це може бути прийнятним.
parvus
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.