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.