Python encodings.utf_8.StreamReader readline()、read()和seek()don';不合作
考虑这个非常简单的例子Python encodings.utf_8.StreamReader readline()、read()和seek()don';不合作,python,python-3.x,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
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。如果您只需交换代码,您的代码就可以工作
reader = codecs.getreader("UTF-8")
stream = reader(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()
请注意对
行的更改。append()
如果您只需交换代码,则代码将正常工作
reader = codecs.getreader("UTF-8")
stream = reader(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()
请注意对
行.append()的更改您不想使用编解码器
流读取器。它们是实现分层I/O以处理文本编码和解码的一种较旧、过时的尝试,因为它被更健壮、更快的实现所取代。已经有了
您确实希望将编解码器.getreader()
的使用替换为:
此时,while
循环起作用,行
结束为['Some line without comment\n']
您也不需要在此处使用seek或tell()。您可以直接在文件对象(包括TextIOWrapper()
对象)上循环:
甚至:
lines = [l for l in stream if not l.startswith('#')]
如果您担心TextIOWrapper()
wrapper对象在不再需要包装器时关闭底层流,只需首先分离包装器:
stream.detach()
您不想使用编解码器
流阅读器。它们是实现分层I/O以处理文本编码和解码的一种较旧、过时的尝试,因为它被更健壮、更快的实现所取代。已经有了
您确实希望将编解码器.getreader()
的使用替换为:
此时,while
循环起作用,行
结束为['Some line without comment\n']
您也不需要在此处使用seek或tell()。您可以直接在文件对象(包括TextIOWrapper()
对象)上循环:
甚至:
lines = [l for l in stream if not l.startswith('#')]
如果您担心TextIOWrapper()
wrapper对象在不再需要包装器时关闭底层流,只需首先分离包装器:
stream.detach()
是的,没错,但使用reader很重要。这只是一个简单的例子-最小工作示例是的,这是真的,但使用reader很重要。这只是一个简单的示例-最小工作示例我建议始终先读取该行,然后检查结果字符串的第一个字符,以决定是否将该行附加到列表中。这似乎是一个错误。如果你坚持使用StreamReader
,那么我鼓励你阅读整个政治公众人物,至少你会知道会发生什么。我的意见是写在墙上,你真的应该找到另一种方法。我建议你总是先读这行,然后检查结果字符串的第一个字符,以决定是否将这行附加到你的列表中。这似乎是一个错误。如果你坚持使用StreamReader
,那么我鼓励你阅读整个政治公众人物,至少你会知道会发生什么。我的意见是,写东西是在墙上,你真的应该找到另一种方法。TextIOWrapper是一个伟大的解决方案,但我不能使用它,因为它的垃圾收集太早,它关闭了流@Joozty我认为您有更好的机会克服TextIOWrapper
问题,而不是StreamReader
问题。但是,如果没有看到您试图做的事情的实际例子,就很难提供有用的建议,问题中的代码似乎不是这样。@Joozty链接问题的公认答案解释了如何避免TextIOWrapper
关闭流。如果这不能解决您的问题,您应该在问题中解释原因。@Joozty:您可以通过再次断开TextIOWrapper
对象来避免这一问题;调用stream.detach()。我给这个问题添加了一个答案,完全没有必要因为包装器超出范围而进行这些长度的测试。@Joozty:只是提醒一下:您链接的问题的OP现在已将我的答案标记为已接受。TextIOWrapper是一个很好的解决方案,但我不能使用它,因为它的垃圾收集太早,并且会关闭流@Joozty我认为您有更好的机会克服TextIOWrapper
问题,而不是StreamReader
问题。但是,如果没有看到您试图做的事情的实际例子,就很难提供有用的建议,问题中的代码似乎不是这样。@Joozty链接问题的公认答案解释了如何避免TextIOWrapper
关闭流。如果这不能解决您的问题,您应该在问题中解释原因。@Joozty:您可以通过断开Tex来避免这一问题