Как решить "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. 
