从文件末尾寻求抛出不支持的异常

时间:2014-02-03 17:14:25

标签: python file python-3.3

我有这个代码片段,我正试图使用​​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

我在这里遗漏了什么吗?

4 个答案:

答案 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

解决方案

将这些信息放在一起,我们可以实现OP的目标:

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)