28

我试图理解io.BytesIO的write()read()方法。我的理解是我可以像使用 File 对象一样使用io.BytesIO 。

import io
in_memory = io.BytesIO(b'hello')
print( in_memory.read() )

上面的代码将按预期返回b'hello',但下面的代码将返回一个空字符串b''

import io
in_memory = io.BytesIO(b'hello')
in_memory.write(b' world')
print( in_memory.read() )

我的问题是:

-具体在io.BytesIO.write(b' world')做什么?

- io.BytesIO.read()io.BytesIO.getvalue()有什么区别?

我认为答案与io.BytesIO是一个流对象有关,但我并不清楚大局。

4

3 回答 3

27

问题是您位于流的末尾。把这个位置想象成一个光标。一旦你写b' world'了,你的光标就在流的末尾。当您尝试 时.read(),您正在读取光标位置之后的所有内容 - 这没什么,所以您得到空字节串。

要在流中导航,您可以使用以下.seek方法:

>>> import io
>>> in_memory = io.BytesIO(b'hello', )
>>> in_memory.write(b' world')
>>> in_memory.seek(0)  # go to the start of the stream
>>> print(in_memory.read())
b' world'

请注意,就像write( 'w') 模式下的文件流一样,初始字节b'hello'已被您写入的b' world'.

.getvalue()无论当前位置如何,都只返回流的全部内容。

于 2018-11-26T17:00:55.617 回答
9

这是一个内存流,但仍然是一个流。位置已存储,因此与任何其他流一样,如果您在写入后尝试读取,则必须重新定位:

import io
in_memory = io.BytesIO(b'hello')
in_memory.seek(0,2)   # seek to end, else we overwrite
in_memory.write(b' world')
in_memory.seek(0)    # seek to start
print( in_memory.read() )

印刷:

b'hello world'

whilein_memory.getvalue()不需要 final seek(0),因为它从位置 0 返回流的内容。

于 2018-11-26T16:59:02.653 回答
4

BytesIO确实表现得像一个文件,只有一个您可以读取和写入的文件。令人困惑的部分可能是读写位置是相同的。所以首先你要做:

in_memory = io.BytesIO(b'hello')

这为您提供了一个字节缓冲区,in_memory其中包含内容b'hello'和开头的读/写位置(在 first 之前b'h')。当你这样做时:

in_memory.write(b' world')

您正在有效地覆盖b'hello'b' world'并且实际上进一步获得一个字节),现在您的位置位于末尾(在 last 之后b'd')。所以当你这样做时:

print( in_memory.read() )

您什么也看不到,因为在当前位置之后没有什么可读取的。但是,您可以使用seek来移动位置,所以如果您这样做

import io
in_memory = io.BytesIO(b'hello')
in_memory.write(b' world')
in_memory.seek(0)
print( in_memory.read() )

你得到:

b' world'

请注意,您看不到初始值b'hello',因为它已被覆盖。如果要在初始内容之后再写,可以先寻尾:

import io
in_memory = io.BytesIO(b'hello')
in_memory.seek(0, 2)
in_memory.write(b' world')
in_memory.seek(0)
print( in_memory.read() )

输出:

b'hello world'

编辑: About getvalue,正如其他答案所指出的那样,它为您提供了完整的内部缓冲区,与当前位置无关。此操作显然不适用于文件。

于 2018-11-26T17:02:30.503 回答