ser*_*eek 24 python file python-3.3
我有这个代码片段,我试图使用python从文件末尾向后搜索:
f=open('D:\SGStat.txt','a');
f.seek(0,2)
f.seek(-3,2)
Run Code Online (Sandbox Code Playgroud)
这会在运行时抛出以下异常:
f.seek(-3,2)
io.UnsupportedOperation: can't do nonzero end-relative seeks
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
jon*_*rpe 36
从Python 3.2及更高版本的文档:
在文本文件(那些
b在模式字符串中没有打开的文件)中,只允许相对于文件开头的搜索(异常是寻找到文件结尾seek(0, 2)).
因此,您可以将程序更改为:
f = open('D:\SGStat.txt', 'ab')
f.seek(0, 2)
f.seek(-3, 2)
Run Code Online (Sandbox Code Playgroud)
但是,您应该知道b在读取或写入文本时添加标志可能会产生意想不到的后果(例如,使用多字节编码),实际上会更改读取或写入的数据类型.有关问题原因的更全面讨论以及不需要添加b标记的解决方案,请参阅此问题的另一个答案.
Eri*_*sey 28
现有的答案确实回答了这个问题,但没有提供解决方案.
来自readthedocs:
如果文件以文本模式打开(没有
b),则只返回的偏移tell()是合法的.使用其他偏移会导致未定义的行为.
在文本文件中(那些
b在模式字符串中没有打开的文件),只允许相对于文件[os.SEEK_SET]的开头查找...
这意味着如果你有来自旧Python的代码:
f.seek(-1, 1) # seek -1 from current position
Run Code Online (Sandbox Code Playgroud)
它在Python 3中看起来像这样:
f.seek(f.tell() - 1, os.SEEK_SET) # os.SEEK_SET == 0
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
Eric Lindsey 的答案不起作用,因为 UTF-8 文件每个字符可以有多个字节。更糟糕的是,对于我们这些以英语为第一语言并仅使用英语文件的人来说,它可能只工作足够长的时间才能进入生产代码并真正破坏东西。
...但它现在确实适用于 UTF-8,至少可以追溯到 Python 3.7,至少可以达到 Python 3.12
要在文本模式下向后查找文件,只要正确处理由于UnicodeDecodeError查找不是 UTF-8 字符开头的字节而导致的问题,就可以这样做。由于我们正在向后查找,因此我们可以简单地向后查找一个额外的字节,直到找到字符的开头。
f.tell()至少目前,结果仍然是 UTF-8 文件在文件中的字节位置。因此,f.seek()当您随后使用无效偏移量时,将引发 UnicodeDecodeError f.read(),并且可以通过再次将其纠正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)
Run Code Online (Sandbox Code Playgroud)