Python io.BytesIO 的 write()、read() 和 getvalue() 方法如何工作?

How the write(), read() and getvalue() methods of Python io.BytesIO work?

我正在尝试理解 write()read() 方法 io.BytesIO。 我的理解是我可以像使用文件一样使用 io.BytesIO 对象。

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

上面的代码会 return b'hello' 正如预期的那样,但是下面的代码会 return 一个空字符串 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 是流对象有关,但我不清楚大局。

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

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'

in_memory.getvalue() 不需要最后的 seek(0) 因为它 returns 从位置 0 开始的流内容。

问题是您位于流的末尾。将位置想象成光标。写入 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() 只是 returns 流的全部内容,无论当前位置如何。

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

in_memory = io.BytesIO(b'hello')

这会在 in_memory 中为您提供一个字节缓冲区,其中包含内容 b'hello' 并且 read/write 位置位于开头(在第一个 b'h' 之前)。当你这样做时:

in_memory.write(b' world')

您实际上是用 b' world' 覆盖了 b'hello'(实际上又多了一个字节),现在您的位置在末尾(在最后一个 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'

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