Python ikili bir dosyaya nasıl yazılır?


128

Tamsayı olarak bayt listem var, bu da şöyle bir şey

[120, 3, 255, 0, 100]

Bu listeyi ikili olarak bir dosyaya nasıl yazabilirim?

Bu işe yarar mı?

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

60
"Bu işe yarar mı?" Diye soruyorsunuz. Bunu denediniz mi?
— StephenTG

1
Olmalı TypeError: argument 1 must be string or buffer, not list.
— anatoly techtonik

Yanıtlar:


128

Bu tam olarak ne bytearrayiçindir:

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

Python 3.x kullanıyorsanız, bytesbunun yerine kullanabilirsiniz (ve muhtemelen niyetinizi daha iyi gösterdiği için kullanmalısınız). Ama Python 2.x, o olmaz iş, çünkü bytessadece bir takma addır str. Her zaman olduğu gibi, etkileşimli tercümanla göstermek metinle açıklamadan daha kolaydır, o yüzden bunu yapayım.

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
Yerleşik türlerin güzel kullanımı. Bytearray'in 2.6'da eklendiğini unutmayın, eski sistemleri desteklemek istiyorsanız, bundan kaçınılmalıdır.
— Perkins

7
@Perkins: Elbette, 2.3 üzerinde çalışmanız gerekiyorsa jeneratör ifadelerinden kaçınmalısınız, ikisine de dikkat edin str.encodeve struct.pack2.2 üzerinde çalışmanız gerekiyorsa. Ancak 2.6, 5 yıldır çıktı; üç Ubuntu LTS'nin tümü hala desteklenmektedir, üç OS X sürümü de desteklenmektedir, CentOS / RHEL'in önceki ana sürümü vb. hepsi yerleşik olarak gelir. 2.5 veya 2.1 veya 1.6 veya her neyse, desteklemeniz gerekiyorsa, muhtemelen biliyorum…
— abarnert

4
Windows üzerinde Python 2 ile, bir yazma bulundu bytearrayhala dönüştürür \niçin \r\ndosyayı açarken "b", bayrağı geçirilen değilse, ikili veri için bu yetersiz hale.
— feersum

6
@feersum: Tabii ki; 2.x'te ikili ve metin modunun anlamı budur . Baytlarınızın hangi türden geldiği önemli değildir. (3.x sürümünde, elbette, ikili ve metin modu, bayt ve unicode yazdığınız anlamına gelir ve \r\nözellik, metin için evrensel yeni satır seçeneklerinin bir parçasıdır.)
— abarnert

Bytearray () 'in dosya yazmak için iyi bir seçim olduğundan emin değilim. Boyutu yönetilebilir parçalarla sınırlamanız gerekir. Aksi takdirde, dosyalarınız çok yükseldiğinde belleğiniz tükenir.
— mckenzm

31

struct.packTamsayı değerlerini ikili bayta dönüştürmek için kullanın , ardından baytları yazın. Örneğin

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

Ancak bir ikili dosyaya asla bir .txtuzantı vermem .

Bu yöntemin yararı, diğer türler için de işe yaramasıdır; örneğin, değerlerden herhangi biri 255'ten büyükse '5i', tam 32 bit tam sayılar elde etmek yerine biçim için kullanabilirsiniz .


.txt, yazdığınız verilerin hepsinin yazdırılabilir ascii aralığına girdiğini bilmenin bir yolu varsa sorun değil. Ancak haklısınız, sanırım bu durumda, örnek veriler yazdırılamayan karakterler içerdiğinden.
— Perkins

@Perkins Değerlerin ASCII aralığında 256'dan daha az olacağı varsayımında bulunmadım. Öyle olsalar bile, .txt dosyaları hiçbir zaman ikili verilere uygulanmayan bir insan için anlamlı olan dosyalar için ayrılmalıdır.
— Mark Ransom

1
Haklısın, struct.pack ayrıca 255'in üzerinde değerlerle veri yazacaksanız da gidilecek yoldur, çünkü ne bytearray ne de chr daha büyük tamsayı değerlerini işleyemez.
— Perkins

1
@MarkRansom: Evet, bu hala daha genel bir soruna kesinlikle iyi bir çözüm: "Bazı tam sayıların rastgele ama sabit boyutta bir listem var, bunları bir ikili dosyaya nasıl yazabilirim?" ve bu soruyu arayan ve bu soruyu bulan insanları görebiliyorum…
— abarnert

1
struct.pack daha iyi bir cevaptır; basitçe bir arka plan oluşturmaktan çok daha esnektir.
— Seth

12

256'dan küçük tamsayılardan ikiliye dönüştürmek için chrişlevi kullanın . Yani aşağıdakileri yapmaya bakıyorsunuz.

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

1
<128 demek olmalısınız. Python3'ün şikayet ettiği gibi: UnicodeEncodeError: 'ascii' codec'i 0 konumunda '\ x89' karakterini kodlayamıyor: ordinal aralık (128) içinde değil
— uygun

2
Hayır, <256 demek istiyorum, ancak kodlama charmapdaha çok olmalı asciive python2 ve python3'te çalışıyor. asciiKodlama sadece python2 çalışır.
— Perkins

9

Python 3.2+ itibariyle, bunu to_bytesyerel int yöntemini kullanarak da gerçekleştirebilirsiniz :

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

Yani, to_bytesbu durumda yapılan her bir çağrı , karakterleri büyük endian sırasına göre düzenlenmiş (uzunluk-1 dizeleri için önemsizdir) ve tamsayı değerini temsil eden 1 uzunluğunda bir dize oluşturur byte. Ayrıca son iki satırı tek bir satırda kısaltabilirsiniz:

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

8

Python 3 sözdizimini kullanarak aşağıdaki kod örneğini kullanabilirsiniz:

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

İşte tek astarlı kabuk:

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

0

Turşu kullanın, bunun gibi: turşu ithal edin

Kodunuz şöyle görünecektir:

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

Verileri geri okumak için pickle.load yöntemini kullanın


3
Bu, tek içeriğin 120, 3, 255, 0, 100 olduğu 5 bayt uzunluğunda bir ikili dosya oluşturmaz. Kapalı bir sistemde, yine de bu kabul edilebilir.
— parvus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.