web-dev-qa-db-ja.com

バイナリストリームの「open」と「io.BytesIO」の違い

私はPythonでストリームを操作することを学んでいますが、 IO docs が次のように言っていることに気付きました:

バイナリストリームを作成する最も簡単な方法は、モード文字列に 'b'を指定したopen()を使用することです。

f = open("myfile.jpg", "rb")

インメモリバイナリストリームは、BytesIOオブジェクトとしても利用できます。

f = io.BytesIO(b"some initial binary data: \x00\x01")

fで定義されているopenfで定義されているBytesIOの違いは何ですか。言い換えれば、「インメモリバイナリストリーム」を構成するものと、openの機能との違いは何ですか?

44
Luke Whyte

簡単にするために、今は読む代わりに書くことを考えてみましょう。

したがって、次のようにopen()を使用すると、

with open("test.dat", "wb") as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")

実行後、test.datというファイルが作成され、Hello Worldが含まれます。データは、ファイルに書き込まれた後、メモリに保持されません(名前で保持されている場合を除く)。

代わりにio.BytesIO()を検討する場合:

with io.BytesIO() as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")

内容をファイルに書き込む代わりに、メモリ内のバッファーに書き込みます。言い換えれば、RAMのチャンクです。基本的に、次の記述は同等です。

buffer = b""
buffer += b"Hello World"
buffer += b"Hello World"
buffer += b"Hello World"

withステートメントを使用した例に関連して、最後にdel bufferもあります

ここでの主な違いは、最適化とパフォーマンスです。 io.BytesIOは、すべてのb"Hello World"を1つずつ連結するよりも高速にするいくつかの最適化を実行できます。

ここにそれを証明するための小さなベンチマークがあります:

  • 連結:1.3529秒
  • BytesIO:0.0090秒
import io
import time

begin = time.time()
buffer = b""
for i in range(0, 50000):
    buffer += b"Hello World"
end = time.time()
seconds = end - begin
print("Concat:", seconds)

begin = time.time()
buffer = io.BytesIO()
for i in range(0, 50000):
    buffer.write(b"Hello World")
end = time.time()
seconds = end - begin
print("BytesIO:", seconds)

パフォーマンスの向上に加えて、連結の代わりにBytesIOを使用すると、ファイルオブジェクトの代わりにBytesIOを使用できるという利点があります。したがって、ファイルオブジェクトへの書き込みを予期する関数があるとします。その後、ファイルの代わりにそのメモリ内バッファを与えることができます。

違いは、open("myfile.jpg", "rb")は単にmyfile.jpgの内容をロードして返すことです。一方、BytesIOは、一部のデータを含む単なるバッファです。

BytesIOは単なるバッファであるため、コンテンツを後でファイルに書き込む場合は、次のようにする必要があります。

buffer = io.BytesIO()
# ...
with open("test.dat", "wb") as f:
    f.write(buffer.getvalue())

また、あなたはバージョンについて言及しなかった;私はPythonを使用している3.例に関連して:f.close()を呼び出す代わりにwithステートメントを使用している

60
Vallentin

openを使用すると、ハードドライブ上のファイルが開きます。使用するモードに応じて、ディスクから読み取りまたは書き込み(または両方)を実行できます。

BytesIOオブジェクトは、ディスク上の実際のファイルに関連付けられていません。ファイルのように動作するメモリの塊です。 openから返されるファイルオブジェクトと同じAPIを使用します(モードr+bで、バイナリデータの読み取りと書き込みが可能)。

BytesIO(そして、常に兄弟であるStringIOは常にテキストモードです)は、ファイルオブジェクトが与えられることを期待しているAPIにデータを渡す必要があるときに便利です。データを直接渡すことを好みます。ライブラリに渡す前に、入力データをBytesIOにロードできます。戻った後、getvalue()メソッドを使用して、ライブラリがBytesIOからファイルに書き込んだデータを取得できます。 (通常、それらのうちの1つを実行するだけで十分です。)

8
Blckknght
f = open("myfile.jpg", "rb")

ディスクdiskからファイルからバイトを読み取り、メモリ内のPythonによって保持される 'f'として参照されるオブジェクトにそのような値を割り当てます。

f = io.BytesIO(b"some initial binary data: \x00\x01")

バイトストリーム値を、メモリ内のPythonによって保持される 'f'として参照されるオブジェクトに割り当てます。

0
szerszen