io.BufferedReader的peek函数返回缓冲区中的所有文本

9 投票
1 回答
6500 浏览
提问于 2025-04-18 11:28

我在Windows 8上使用Python 3.4.1。

我想读取一个文件,使用一种可以提前查看一定数量字节的缓冲接口,同时也能读取字节。看起来io.BufferedReader是个不错的选择。

可惜的是,io.BufferedReader.peek似乎没什么用,因为它好像只是返回缓冲区里所有的字节,而不是我请求的数量。实际上,这在这个函数的文档中是允许的(我强调的部分):

peek([size]) 从流中返回字节,而不移动位置。最多只会对原始流进行一次读取来满足这个调用。返回的字节数可能会少于或多于请求的数量。

为了展示我认为的无用行为,我有一个名为Test1.txt的测试文件:

first line
second line
third line

我在IDLE中这样创建io.BufferedReader对象:

>>> stream = io.BufferedReader(io.FileIO('Test1.txt'))

然后我请求两个字节,

>>> stream.peek(2)
b'first line\r\nsecond line\r\nthird line'

咦?这就是我系统默认缓冲区大小里的所有文本(在我的系统上是8192字节)。如果我改变这个默认值,我可以确认peek()只是返回了缓冲区的内容,

>>> stream2 = io.BufferedReader(io.FileIO('Test1.txt'), buffer_size=2)
>>> stream2.peek(17)
b'fi'
>>> stream2.peek(17)
b'fi'
>>> stream2.read(2)
b'fi'
>>> stream2.peek(17)
b'rs'

为了明确,以下是我期望看到的输出:

>>> stream = io.BufferedReader(io.FileIO('Test1.txt'))
>>> stream.peek(2)
b'fi'
>>> stream.read(1)
b'f'
>>> stream.peek(2)
b'ir'

也就是说,一个典型的缓冲流。

我在构造这个BufferedReader时做错了什么?我该如何在Python 3.4.1中观察到我期望的行为呢?

1 个回答

5

.peek() 的确是用来返回当前的缓冲区内容。如果你把它和 .read() 一起使用,你会发现每次读取后,缓冲区返回的数据会越来越少,直到缓冲区再次被填满。

对于 .peek() 的大多数用途来说,这样的设计是完全可以接受的。当缓冲区为空时,返回的字节数可以帮助你限制从底层输入输出源预期获取的数据量,这一点在该源在读取时可能会阻塞的情况下尤其重要。

你只需要对返回的值进行切片处理:

stream.peek(num)[:num]

撰写回答