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
การใช้งานประเภท builtin ที่ดี โปรดทราบว่า bytearray ถูกเพิ่มเข้ามาใน 2.6 หากคุณต้องการรองรับระบบเดิมควรหลีกเลี่ยง
Perkins

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 โหมดไบนารีเทียบกับข้อความหมายความว่าคุณเขียนไบต์เทียบกับยูนิโคดและ\r\nคุณลักษณะนี้เป็นส่วนหนึ่งของตัวเลือกการขึ้นบรรทัดใหม่สากลสำหรับข้อความ)
ยกเลิก

ฉันไม่แน่ใจว่า bytearray () เป็นตัวเลือกที่ดีสำหรับการเขียนไฟล์ คุณจะต้อง จำกัด ขนาดของชิ้นส่วนที่จัดการได้ มิฉะนั้นเมื่อขนาดไฟล์ของคุณสูงเกินไปคุณจะมีหน่วยความจำหมด
mckenzm

31

ใช้struct.packเพื่อแปลงค่าจำนวนเต็มเป็นไบต์ไบนารีจากนั้นเขียนไบต์ เช่น

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

แต่ฉันจะไม่ให้ไฟล์ไบนารี.txtขยาย

ข้อดีของวิธีนี้คือใช้ได้กับประเภทอื่น ๆ เช่นหากค่าใด ๆ มากกว่า 255 คุณสามารถใช้'5i'สำหรับรูปแบบแทนเพื่อรับจำนวนเต็ม 32 บิตแบบเต็ม


.txt จะดีถ้าคุณมีวิธีรู้ว่าข้อมูลที่คุณกำลังเขียนทั้งหมดอยู่ในช่วง ascii ที่พิมพ์ได้ อย่างไรก็ตามคุณถูกต้องฉันคิดว่าในกรณีนี้เนื่องจากข้อมูลตัวอย่างมีอักขระที่ไม่สามารถพิมพ์ได้
Perkins

@ เพอร์กินส์ฉันไม่ได้ตั้งสมมติฐานว่าค่าจะน้อยกว่า 256 ในช่วง ASCII แม้ว่าจะเป็นไฟล์. txt ก็ตามควรสงวนไว้สำหรับไฟล์ที่เหมาะสมกับมนุษย์ซึ่งไม่เคยใช้กับข้อมูลไบนารี
Mark Ransom

1
คุณถูกต้องแล้ว struct.pack ยังเป็นวิธีที่จะไปหากคุณกำลังจะเขียนข้อมูลที่มีค่าสูงกว่า 255 เนื่องจากทั้ง bytearray หรือ chr ไม่สามารถจัดการกับค่าจำนวนเต็มขนาดใหญ่ได้
Perkins

1
@MarkRansom: นี่ยังคงเป็นทางออกที่ดีสำหรับปัญหาทั่วไปของ "ฉันมีรายการจำนวนเต็มของขนาดตามอำเภอใจ แต่คงที่ฉันจะเขียนลงในไฟล์ไบนารีได้อย่างไร" และฉันเห็นคนค้นหาคำถามนั้นและพบคำถามนี้…
abarnert

1
struct.pack คือคำตอบที่ดีกว่า มีความยืดหยุ่นมากกว่าการสร้าง bytearray
Seth

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 เท่านั้น
Perkins

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 กับตัวละครของมันจัดอยู่ในลำดับ big-(ซึ่งเป็นที่น่ารำคาญสำหรับความยาว-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])))'

0

ใช้ผักดองเช่นนี้นำเข้าผักดอง

รหัสของคุณจะมีลักษณะดังนี้:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.