Как решить "OSError: указание позиции отключено по вызову next ()"
Я создаю систему редактирования файлов и хотел бы сделать функцию tell() на основе строки вместо байтовой. Эта функция будет использоваться внутри цикла "with" с вызовом open(file). Эта функция является частью класса, который имеет:
self.f = open(self.file, 'a+')
# self.file is a string that has the filename in it
ниже исходной функции (Он также имеет параметр char, если вы хотите вернуть строку и Байт):
def tell(self, char=False):
t, lc = self.f.tell(), 0
self.f.seek(0)
for line in self.f:
if t >= len(line):
t -= len(line)
lc += 1
else:
break
if char:
return lc, t
return lc
проблема, с которой я сталкиваюсь, заключается в том, что это возвращает OSError и связано с тем, как система повторяет файл, но я не понимаю проблему. Спасибо всем, кто может помочь.
3 ответов
у меня есть более старая версия Python 3, и я на Linux вместо Mac, но мне удалось воссоздать что-то очень близкое к вашей ошибке:
IOError: telling position disabled by next() call
An IO ошибки, а не OS ошибки, но в остальном то же самое. Как ни странно, я не мог вызвать его с помощью open('a+', ...)
, но только при открытии файла в режиме чтения: open('r+', ...)
.
дальнейшая путаница заключается в том, что ошибка исходит от _io.TextIOWrapper
, класс, появляется будет определен в ... Я подчеркиваю "появляется", потому что:
на
TextIOWrapper
в этом файле есть такие атрибуты, как_telling
что я не могу получить доступ к объекту whatever-it-is, называющему себя_io.TextIOWrapper
.на
TextIOWrapper
класс_pyio.py
не делает никакого различия между читаемыми, записываемыми или случайными файлами. Либо оба должны работать, либо оба должны поднять то же самоеIOError
.
независимо от того,TextIOWrapper
класс, как описано в запрещает tell
метод во время итерации. Кажется, это то, с чем вы сталкиваетесь (комментарии мои):
def __next__(self):
# Disable the tell method.
self._telling = False
line = self.readline()
if not line:
# We've reached the end of the file...
self._snapshot = None
# ...so restore _telling to whatever it was.
self._telling = self._seekable
raise StopIteration
return line
в своем tell
метод, вы почти всегда break
из итерации, прежде чем она достигнет конца файла, оставив _telling
отключен (False
):
еще один способ сброса _telling
is the flush
метод, но он также не удался при вызове во время итерации:
IOError: can't reconstruct logical file position
путь вокруг этого, по крайней мере на моей системе, это вызов seek(0)
на TextIOWrapper
, который восстанавливает все до известного состояния (и успешно вызывает flush
в придачу):
def tell(self, char=False):
t, lc = self.f.tell(), 0
self.f.seek(0)
for line in self.f:
if t >= len(line):
t -= len(line)
lc += 1
else:
break
# Reset the file iterator, or later calls to f.tell will
# raise an IOError or OSError:
f.seek(0)
if char:
return lc, t
return lc
если это не решение для вашей системы, он может по крайней мере сказать вам, где начать смотреть.
PS: вы должны рассмотреть всегда возврат номера строки и смещения символов. Функции, которые могут возвращать совершенно разные типы, трудно иметь дело с - - - намного проще для вызывающего абонента просто выбросить значение, которое ей или ей не нужно.
Я не знаю, была ли это первоначальная ошибка, но вы можете получить ту же ошибку, если попытаетесь вызвать f.tell () внутри строчной итерации файла типа so:
with open(path, "r+") as f:
for line in f:
f.tell() #OSError
который можно легко заменить следующим:
with open(path, mode) as f:
line = f.readline()
while line:
f.tell() #returns the location of the next line
line = f.readline()
просто быстрый обходной путь для этой проблемы:
как вы перебираете файл с самого начала в любом случае, просто отслеживать, где вы находитесь с выделенной переменной:
file_pos = 0
with open('file.txt', 'rb') as f:
for line in f:
# process line
file_pos += len(line)
Теперь file_pos
будет всегда, что file.tell()
б рассказать вы. Обратите внимание, что это работает только для ASCII-файлов, так как tell и seek работают с байтовыми позициями. Работая на линейной основе, легко конвертировать строки из байта в строки unicode.