二进制流中`open`和`io.BytesIO`之间的区别

Luk*_*yte 51 python io stream

我正在学习如何使用Python中的流,我注意到IO文档说如下:

创建二进制流的最简单方法是在模式字符串中使用open()和'b':

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

内存中的二进制流也可用作BytesIO对象:

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

f由定义openf定义之间的区别是什么BytesIO.换句话说,是什么构成了"内存中的二进制流",这与它的不同之处是什么open

Val*_*tin 64

为简单起见,我们现在考虑写作而不是阅读.

所以当你使用时open()说:

with open("test.dat", "wb") as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")
Run Code Online (Sandbox Code Playgroud)

执行后,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")
Run Code Online (Sandbox Code Playgroud)

它不是将内容写入文件,而是写入内存缓冲区.换句话说,一块RAM.基本上写下以下内容将是等效的:

buffer = b""
buffer += b"Hello World"
buffer += b"Hello World"
buffer += b"Hello World"
Run Code Online (Sandbox Code Playgroud)

关于带有with语句的示例,最后还会有一个del buffer.

这里的关键区别是优化和性能.io.BytesIO能够进行一些优化,使其比简单地b"Hello World"逐个连接所有更快.

只是为了证明它是一个小基准:

  • 康卡特: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)
Run Code Online (Sandbox Code Playgroud)

除了性能增益之外,使用BytesIO而不是连接具有BytesIO可以用来代替文件对象的优点.所以说你有一个期望文件对象写入的函数.然后你可以给它内存缓冲区而不是文件.

不同之处在于open("myfile.jpg", "rb")只需加载并返回内容myfile.jpg; 然而,BytesIO再次只是一个包含一些数据的缓冲区.

因为BytesIO它只是一个缓冲区 - 如果你想稍后将内容写入文件 - 你必须这样做:

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

另外,你没有提到一个版本; 我正在使用Python 3.与示例相关:我使用的是with语句而不是调用f.close()

  • 很好的答案; 问题提到`在内存流中`并且你在内存缓冲区中引用了`.Python有区别吗?值得简要谈谈.从英语语义的角度来看,"stream"意味着从源到接收(从源推送)的连续比特流,其中缓冲区意味着源中的比特缓存准备好从源中快速获取块或块(槽下拉)来源). (3认同)

Blc*_*ght 8

使用open打开硬盘上的文件.根据您使用的模式,您可以从磁盘读取或写入(或两者).

一个BytesIO对象不与磁盘上的任何真正的文件关联.它只是一块内存,就像文件一样.它与返回的文件对象具有相同的API open(使用模式r+b,允许读取和写入二进制数据).

BytesIO(StringIO当它需要将数据传递给期望获得文件对象的API时,或者您希望直接传递数据的位置时,它可能非常有用).您可以将输入数据加载BytesIO到库中之前加载.返回后,您可以BytesIO使用该getvalue()方法获取库写入文件的任何数据.(当然,你通常只需要做其中一个.)