Skip to main content
 首页 » 编程设计

python之encodings.utf_8.StreamReader readline(), read() 和 seek() 不合作

2025年05月04日13shanyou

考虑这个非常简单的例子。

import codecs 
from io import BytesIO 
 
string = b"""# test comment 
Some line without comment 
# another comment 
""" 
 
reader = codecs.getreader("UTF-8") 
stream = reader(BytesIO(string)) 
 
lines = [] 
while True: 
    # get current position 
    position = stream.tell() 
 
    # read first character 
    char = stream.read(1) 
 
    # return cursor to start 
    stream.seek(position, 0) 
 
    # end of stream 
    if char == "": 
        break 
 
    # line is not comment 
    if char != "#": 
        lines.append(stream.readline()) 
        continue 
 
    # line is comment. Skip it. 
    stream.readline() 
 
print(lines) 
assert lines == ["Some line without comment\n"] 

我正在尝试从 StreamReader 逐行读取,如果该行以 # 开头,我将跳过它,否则我将其存储在列表中。但是当我使用 seek() 方法时有一些奇怪的行为。似乎 seek() 和 readline() 不合作并将光标移动到很远的地方。结果列表为空。

当然我可以用不同的方式来做。但正如我在上面所写,这是一个非常简单的示例,它可以帮助我理解事物是如何协同工作的。

我使用 Python 3.5。

请您参考如下方法:

您不想使用编解码器 流阅读器。自从被 io module 取代以来,它们是实现分层 I/O 以处理文本编码和解码的较旧、过时的尝试。 ,一个更健壮和更快的实现。已有serious calls for the stream readers to be deprecated .

您真的想用 io.TextIOWrapper() object 替换您对 codecs.getreader() 的使用:

import codecs 
from io import BytesIO, TextIOWrapper 
 
string = b"""# test comment 
Some line without comment 
# another comment 
""" 
 
stream = TextIOWrapper(BytesIO(string)) 

此时 while 循环起作用并且 lines 结束为 ['Some line without comment\n']。

您也不需要在此处使用搜索或 tell()。您可以直接在文件对象(包括 TextIOWrapper() 对象)上循环:

lines = [] 
for line in stream: 
    if not line.startswith('#'): 
        lines.append(line) 

甚至:

lines = [l for l in stream if not l.startswith('#')] 

如果您担心 TextIOWrapper() 包装器对象在您不再需要包装器时关闭底层流,只需先分离包装器:

stream.detach()