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

Joo*_*zty 1 python python-3.x

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

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"]
Run Code Online (Sandbox Code Playgroud)

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

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

我使用Python 3.5.

Mar*_*ers 5

您不想使用codecs流阅读器.它们是一种较旧的,过时的尝试,用于实现分层I/O以处理文本的编码和解码,因为它被io模块取代,实现得更加强大和快速.有人严肃地呼吁不要弃用流阅读器.

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

import codecs
from io import BytesIO, TextIOWrapper

string = b"""# test comment
Some line without comment
# another comment
"""

stream = TextIOWrapper(BytesIO(string))
Run Code Online (Sandbox Code Playgroud)

在这一点上while循环工作并lines最终成为['Some line without comment\n'].

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

lines = []
for line in stream:
    if not line.startswith('#'):
        lines.append(line)
Run Code Online (Sandbox Code Playgroud)

甚至:

lines = [l for l in stream if not l.startswith('#')]
Run Code Online (Sandbox Code Playgroud)

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

stream.detach()
Run Code Online (Sandbox Code Playgroud)