Поиск с конца файла, бросающего неподдерживаемое исключение
У меня есть этот фрагмент кода, и я пытаюсь искать назад с конца файла с помощью 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
Мне что-то здесь не хватает?
Ответы
Ответ 1
Из документации для Python 3.2 и выше:
В текстовых файлах (открытых без строки b
в строке режима) разрешен только поиск относительно начала файла (исключение - поиск в самом конце файла с seek(0, 2)
).
Поэтому вы можете изменить свою программу на следующую:
f = open('D:\SGStat.txt', 'ab')
f.seek(0, 2)
f.seek(-3, 2)
Однако вы должны знать, что добавление флага b
во время чтения или записи текста может иметь непредвиденные последствия (например, с многобайтовым кодированием) и фактически меняет тип читаемых или записываемых данных. Для более подробного обсуждения причины проблемы и решения, которое не требует добавления флага b
, см. Другой ответ на этот вопрос.
Ответ 2
Существующие ответы действительно отвечают на вопрос, но не дают решения.
Из readthedocs:
Если файл открывается в текстовом режиме (без b
), допустимы только смещения, возвращаемые функцией tell()
. Использование других смещений вызывает неопределенное поведение.
Это подтверждается документацией, в которой говорится:
В текстовых файлах (которые открываются без 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
Ответ 3
Чтобы использовать поиск с текущей позиции и конца, вам нужно открыть текстовый файл в двоичном режиме. Посмотрите этот пример, где я создал файл "nums.txt" и поместил в него "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Я читаю буквы строки "PYTHON" из файла и отображаю то же самое. Посмотрите код, который я запускаю в окнах Python 3.6 в Anaconda 4.2
>>> file=open('nums.txt','rb')
>>> file.seek(15,0)
15
>>> file.read(1).decode('utf-8')
'P'
>>> file.seek(8,1)
24
>>> file.read(1).decode('utf-8')
'Y'
>>> file.seek(-7,2)
19
>>> file.read(1).decode('utf-8')
'T'
>>> file.seek(7,0)
7
>>> file.read(1).decode('utf-8')
'H'
>>> file.seek(6,1)
14
>>> file.read(1).decode('utf-8')
'O'
>>> file.seek(-2,1)
13
>>> file.read(1).decode('utf-8')
'N'