1. ホーム
  2. python

[解決済み] バイナリストリームにおける `open` と `io.BytesIO` の相違点

2022-10-19 22:47:28

質問

Pythonでストリームの扱いについて学んでいるのですが、その中で IO ドキュメント は次のように言っています。

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

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

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

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

とはどのような違いがあるのでしょうか? f で定義されているように openf で定義されるように BytesIO . 言い換えれば、何が "インメモリバイナリストリーム" を作り、何がどう違うのでしょうか? open とはどう違うのでしょうか?

どのように解決するのですか?

簡単のために、今は読むことではなく書くことを考えましょう。

そこで 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 というファイルが作成され、その中に 3x 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.3529 秒
  • バイトIO: 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を使用しています。例題に関連して。を呼び出す代わりに with 文を使用しています。 f.close()