Python bagaimana cara menulis ke file biner?

128

Saya memiliki daftar byte sebagai integer, yang kira-kira seperti

[120, 3, 255, 0, 100]

Bagaimana cara menulis daftar ini ke file sebagai biner?

Apakah ini akan berhasil?

newFileBytes = [123, 3, 255, 0, 100]
# make file
newFile = open("filename.txt", "wb")
# write to file
newFile.write(newFileBytes)
Aaron Hiniker
sumber
60
Anda bertanya "Apakah ini akan berhasil?". Apakah kamu sudah mencobanya
StephenTG
1
Seharusnya TypeError: argument 1 must be string or buffer, not list.
anatoly techtonik

Jawaban:

128

Inilah tepatnya bytearrayuntuk:

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

Jika Anda menggunakan Python 3.x, Anda dapat menggunakan bytessebagai gantinya (dan mungkin harus, karena ini menandakan niat Anda lebih baik). Tetapi di Python 2.x, itu tidak akan berfungsi, karena byteshanya alias untuk str. Seperti biasa, menunjukkan dengan interpreter interaktif lebih mudah daripada menjelaskan dengan teks, jadi izinkan saya melakukannya.

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]'
abarnert
sumber
1
Penggunaan tipe bawaan yang bagus. Perhatikan saja bahwa bytearray telah ditambahkan di 2.6, jika Anda ingin mendukung sistem lama, itu harus dihindari.
Perkins
7
@ Perkins: Tentu, dan Anda harus menghindari ekspresi generator jika Anda perlu bekerja pada 2.3, berhati-hatilah dengan keduanya str.encodedan struct.packjika Anda perlu bekerja pada 2.2. Tapi 2.6 telah keluar selama 5 tahun sekarang; ketiga LTS Ubuntu masih mendukung, ketiga versi OS X mendukung, versi utama sebelumnya dari CentOS / RHEL, dll., semuanya disertakan dengan bawaannya. Jika Anda perlu mendukung 2.5 atau 2.1 atau 1.6 atau apa pun, Anda mungkin tahu…
abarnert
4
Dengan Python 2 di Windows, saya menemukan bahwa menulis a bytearraymasih dikonversi \nke \r\n, sehingga tidak memuaskan untuk data biner, jika tanda "b" tidak dilewatkan saat membuka file.
feersum
6
@feersum: Tentu saja; yang ini apa mode teks biner vs berarti di 2.x. Tidak masalah jenis byte Anda berasal. (Dalam 3.x, tentu saja, mode biner vs. teks berarti Anda menulis byte vs. unicode, dan \r\nfiturnya adalah bagian dari opsi baris baru universal untuk teks.)
abarnert
Saya tidak yakin bytearray () adalah pilihan yang baik untuk penulisan file. Anda perlu membatasi ukurannya menjadi potongan yang bisa diatur. Jika tidak, begitu ukuran file Anda terlalu tinggi, Anda akan kehabisan memori.
mckenzm
31

Gunakan struct.packuntuk mengonversi nilai integer menjadi byte biner, lalu tulis byte tersebut. Misalnya

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

Namun saya tidak akan pernah memberikan .txtekstensi file biner .

Manfaat dari metode ini adalah dapat digunakan untuk jenis lain juga, misalnya jika ada nilai yang lebih besar dari 255, Anda dapat menggunakan '5i'format untuk mendapatkan bilangan bulat 32-bit penuh.

Mark Ransom
sumber
.txt baik-baik saja jika Anda memiliki beberapa cara untuk mengetahui bahwa data yang Anda tulis semuanya termasuk dalam rentang ascii yang dapat dicetak. Namun, menurut saya Anda benar dalam kasus ini, karena data contoh menyertakan karakter yang tidak dapat dicetak.
Perkins
@ Perkins Saya tidak berasumsi bahwa nilainya bahkan akan kurang dari 256, apalagi dalam kisaran ASCII. Meskipun demikian, file .txt harus disediakan untuk yang masuk akal bagi manusia yang tidak pernah berlaku untuk data biner.
Mark Ransom
1
Anda benar, struct.pack juga merupakan cara untuk pergi jika Anda akan menulis data dengan nilai di atas 255, karena baik bytearray maupun chr tidak dapat menangani nilai integer yang lebih besar.
Perkins
1
@MarkRansom: Nah, ini jelas masih merupakan solusi yang baik untuk masalah yang lebih umum dari "Saya memiliki daftar bilangan bulat dari beberapa ukuran yang berubah-ubah tetapi tetap, bagaimana saya bisa menuliskannya ke file biner?" dan saya dapat melihat orang-orang mencari pertanyaan itu dan menemukan yang satu ini…
abarnert
1
struct.pack adalah jawaban yang lebih baik; itu jauh lebih fleksibel daripada hanya membuat bytearray.
Seth
12

Untuk mengonversi dari bilangan bulat <256 ke biner, gunakan chrfungsi. Jadi, Anda sedang berusaha melakukan hal berikut.

newFileBytes=[123,3,255,0,100]
newfile=open(path,'wb')
newfile.write((''.join(chr(i) for i in newFileBytes)).encode('charmap'))
Perkins
sumber
1
Anda harus berarti <128. Sebagai python3 mengeluh: UnicodeEncodeError: 'ascii' codec tidak bisa encode karakter '\ x89' di posisi 0: ordinal tidak dalam jangkauan (128)
elig
2
Tidak, maksudku <256, tetapi pengkodean harus charmapbukan ascii, dan bekerja di python2 serta python3. The asciiencoding hanya bekerja di python2.
Perkins
9

Mulai Python 3.2+, Anda juga dapat melakukannya menggunakan to_bytesmetode int asli:

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

Yaitu, setiap panggilan tunggal to_bytesdalam hal ini membuat string dengan panjang 1, dengan karakternya diatur dalam urutan big-endian (yang sepele untuk string panjang-1), yang mewakili nilai integer byte. Anda juga dapat mempersingkat dua baris terakhir menjadi satu:

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

Anda dapat menggunakan contoh kode berikut menggunakan sintaks Python 3:

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

Ini shell one-liner:

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

Gunakan acar, seperti ini: import acar

Kode Anda akan terlihat seperti ini:

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

Untuk membaca kembali data, gunakan metode pickle.load

Raymond Mlambo
sumber
3
Ini tidak menghasilkan file biner dengan panjang 5 byte, di mana satu-satunya konten adalah 120, 3, 255, 0, 100. Dalam sistem tertutup, ini mungkin dapat diterima.
parvus