我有这个代码片段,我正试图使用python从文件末尾向后搜索:
f=open('D:\SGStat.txt','a');
f.seek(0,2)
f.seek(-3,2)
这会在运行时抛出以下异常:
f.seek(-3,2)
io.UnsupportedOperation: can't do nonzero end-relative seeks
我在这里遗漏了什么吗?
答案 0 :(得分:31)
从Python 3.2及更高版本的documentation开始:
在文本文件中(在模式字符串中没有
b
打开的文件文件中),只允许相对于文件开头的搜索(例外是seek(0, 2)
寻找文件末尾)
因此,您可以将程序更改为:
f = open('D:\SGStat.txt', 'ab')
f.seek(0, 2)
f.seek(-3, 2)
但是,您应该知道在读取或写入文本时添加b
标志可能会产生意想不到的后果(例如,使用多字节编码),实际上changes the type of data read or written。有关问题原因的更全面讨论以及不需要添加b
标记的解决方案,请参阅another answer to this question。
答案 1 :(得分:14)
现有答案做可以回答问题,但没有提供解决方案。
来自readthedocs:
如果以文本模式(没有
b
)打开文件,则仅tell()
返回的偏移量是合法的。使用其他偏移量会导致不确定的行为。
the documentation支持这种说法,即:
在文本文件(在模式字符串中打开而没有
b
的文本文件)中,仅允许相对于文件 [{os.SEEK_SET
] 开头的查找...
这意味着如果您具有旧Python的代码:
f.seek(-1, 1) # seek -1 from current position
在Python 3中看起来像这样:
f.seek(f.tell() - 1, os.SEEK_SET) # os.SEEK_SET == 0
f.seek(0, os.SEEK_END) # seek to end of file; f.seek(0, 2) is legal
f.seek(f.tell() - 3, os.SEEK_SET) # go backwards 3 bytes
答案 2 :(得分:2)
要从当前位置和结束使用搜索,您必须以二进制模式打开文本文件。请参阅此示例,其中我创建了一个文件“nums.txt”并在文件中放入了“ABCDEFGHIJKLMNOPQRSTUVWXYZ”。我从文件中读取字符串“PYTHON”的字母并显示相同的字母。请参阅我在anaconda 4.2中的python 3.6窗口中运行的代码
btn.setEnabled(false)
答案 3 :(得分:1)
Eric Lindsey's answer不起作用,因为UTF-8文件每个字符可以有多个字节。更糟糕的是,对于那些说英语为第一语言并仅使用英语文件的人来说,它可能工作了足够长的时间来进入生产代码并真正破坏了事情。
...,但它目前在Python 3.7中适用于UTF-8。
要以文本模式向后搜索文件,只要您正确地处理了由于搜索到不是UTF-8字符开头的字节而引起的UnicodeDecodeError
,就可以这样做。由于我们是向后搜索,因此我们可以简单地向后搜索一个额外的字节,直到找到字符的开头为止。
f.tell()
的结果仍然是UTF-8文件在文件中的字节位置,至少目前是这样。因此,f.seek()
到无效的偏移量将在随后的f.read()
时引发UnicodeDecodeError,并且f.seek()
可以再次将其更正为另一个偏移量。 至少目前如此。
例如,寻找到行首(紧靠\n
之后):
pos = f.tell() - 1
if pos < 0:
pos = 0
f.seek(pos, os.SEEK_SET)
while pos > 0:
try:
character = f.read(1)
if character == '\n':
break
except UnicodeDecodeError:
pass
pos -= 1
f.seek(pos, os.SEEK_SET)