如何解决" OSError:通过next()调用告知位置被禁用"

时间:2015-04-14 03:59:15

标签: python file-io error-handling next

我正在创建一个文件编辑系统,并希望创建一个基于行的tell()函数而不是基于字节的函数。此函数将在打开(文件)调用的“with循环”内使用。此函数是具有以下内容的类的一部分:

self.f = open(self.file, 'a+')
# self.file is a string that has the filename in it

以下是原始功能 (如果你想要行和字节返回,它也有一个字符设置):

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,它与系统如何迭代文件有关,但我不明白这个问题。感谢任何可以提供帮助的人。

4 个答案:

答案 0 :(得分:17)

我不知道这是不是原始错误,但如果你尝试在文件的逐行迭代中调用f.tell(),你可能会得到同样的错误:

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()

答案 1 :(得分:12)

我有一个旧版本的Python 3,而且我使用的是Linux而不是Mac,但我能够重新创建一些非常接近你错误的内容:

IOError: telling position disabled by next() call

IO 错误,而不是 OS 错误,但其他方面相同。很奇怪,我无法使用您的open('a+', ...),但仅在以读取模式打开文件时:open('r+', ...)

更糟糕的是,错误来自_io.TextIOWrapper,一个出现的类要在Python的_pyio.py文件中定义......我强调“出现”,因为:

  1. 该文件中的TextIOWrapper具有_telling等属性,我无法访问自称为_io.TextIOWrapper的任何对象。

    < / LI>
  2. TextIOWrapper中的_pyio.py类在可读,可写或随机访问文件之间没有任何区别。两者都应该有效,或者两者都应该提高IOError

  3. 无论如何,TextIOWrapper文件中描述的_pyio.py类会在迭代进行中禁用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的另一种方法是flush方法,但如果在迭代进行过程中调用它也会失败:

    IOError: can't reconstruct logical file position
    

    至少在我的系统上,解决这个问题的方法是在seek(0)调用TextIOWrapper ,这会将所有内容恢复到已知状态(并成功调用{{讨价还价中的1}}:

    flush

    如果这不是您系统的解决方案,它至少可以告诉您从哪里开始寻找。

    PS:您应该考虑始终返回行号和字符偏移量。可以返回完全不同类型的函数很难处理 - 调用者更容易丢弃她或她不需要的值。

答案 2 :(得分:4)

这个问题的快速解决方法:

当您从头开始迭代文件时,只需使用专用变量跟踪您的位置:

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字符串很容易。

答案 3 :(得分:2)

我有同样的错误:OSError:告诉位置被next()调用禁用,并通过在打开文件时添加'rb'模式来解决该问题。