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

时间:2019-01-24 14:40:05

标签: 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"]

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

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

我使用Python 3.5。

2 个答案:

答案 0 :(得分:5)

您不想使用codecs流阅读器。由于io module已被serious calls for the stream readers to be deprecated取代,这是一种更健壮和更快的实现,因此它们是实现分层I / O以处理文本的编码的较旧的,过时的尝试。已经有io.TextIOWrapper() object

您真的想用https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Promise/all代替对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()包装器对象在不再需要包装器时关闭基础流,则只需先 detach 包装器:

stream.detach()

答案 1 :(得分:1)

只要交换

,您的代码就可以使用
reader = codecs.getreader("UTF-8")
stream = reader(BytesIO(string))

使用

stream = BytesIO(string)

编辑:如果要使用StreamReader,则可以使用tell()摆脱重新定位,因为stream.read()stream.readline()足以重新定位。换句话说,在您当前的代码中,您将重新定位两次。

循环中更改的代码:

    # read first character
    char = stream.read(1)

    # end of stream
    if char == "":
        break

    # line is not comment
    if char != "#":
        lines.append(char + stream.readline())
        continue

    # line is comment. Skip it.
    stream.readline()

请注意对lines.append()的更改