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 2013

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
組み込み型の素晴らしい使い方。bytearrayは2.6で追加されたことに注意してください。レガシーシステムをサポートする場合は、回避する必要があります。
パーキンス

7
@Perkins:もちろん、2.3で作業する必要がある場合はジェネレータ式を避け、両方に注意する必要がある場合、str.encodeおよびstruct.pack2.2で作業する必要がある場合はジェネレータ式を使用しないでください。しかし、2.6は今から5年前にリリースされました。3つすべてのUbuntu LTSがまだサポートされており、3つすべてのOS Xバージョン、以前のメジャーバージョンのCentOS / RHELなどがすべて組み込まれています。2.5または2.1または1.6などをサポートする必要がある場合は、知っています…
abarnert 2013

4
Windows上のPython 2では、ファイルを開くときに "b"フラグが渡されない場合、書き込みはbytearrayまだに変換さ\n\r\n、バイナリデータには不十分であることがわかりました。
feersum 14

6
@feersum:もちろんです。これが、2.xでのバイナリモードテキストモードの意味です。バイトの種類は関係ありません。(もちろん、3.xでは、バイナリモードとテキストモードは、バイトとユニコードを書き込むことを意味し、この\r\n機能は、テキストのユニバーサル改行オプションの一部です。)
abarnert

bytearray()がファイルの書き込みに適しているかどうかはわかりません。サイズを管理可能なチャンクに制限する必要があります。そうしないと、ファイルサイズが高くなりすぎると、メモリが不足します。
mckenzm

30

使用struct.pack次いでバイトを書き込み、バイナリバイトに整数値に変換します。例えば

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

ただし、バイナリファイルには.txt拡張子を付けません。

このメソッドの利点は、他のタイプでも機能することです。たとえば、値のいずれかが255より大きい場合'5i'、代わりに完全な32ビット整数を取得するためにフォーマットに使用できます。


.txtは、書き込み中のデータがすべて印刷可能なASCII範囲内にあることを知る方法がある場合は問題ありません。ただし、サンプルデータには印刷できない文字が含まれているため、この場合は正しいと思います。
パーキンス

@Perkins ASCIIの範囲では、値が256未満になることさえ想定していませんでした。たとえそうであっても、.txtファイルは、バイナリデータには適用されない人間にとって意味のあるもののために予約する必要があります。
Mark Ransom 2013

1
そうです、bytearrayもchrも大きな整数値を処理できないため、struct.packは、255を超える値でデータを書き込む場合にも使用できます。
パーキンス

1
@MarkRansom:ええと、これは「任意の固定サイズの整数のリストがあります。バイナリファイルに書き込むにはどうすればよいですか?」というより一般的な問題に対する確かな優れた解決策です。そして、私はその質問を検索してこれを見つけている人々を見ることができます…
abarnert 2013

1
struct.packがより良い答えです。単にバイト配列を作成するよりもはるかに柔軟です。
セス14

12

256未満の整数から2進数に変換するには、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' codec ca n't encode character '\ x89' in position 0:ordinal not range(128)
elig

2
いいえ、つまり256未満を意味しますが、エンコーディングはでcharmapはなくである必要がasciiあり、python3だけでなくpython2でも機能します。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回の呼び出しで、整数値を表すビッグエンディアン順(長さ1の文字列の場合は簡単です)に文字が配置された長さ1の文字列が作成されますbyte。最後の2行を1行に短縮することもできます。

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.