我正在创建一个文件编辑系统,并希望创建一个基于行的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,它与系统如何迭代文件有关,但我不明白这个问题。感谢任何可以提供帮助的人。
答案 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
文件中定义......我强调“出现”,因为:
该文件中的TextIOWrapper
具有_telling
等属性,我无法访问自称为_io.TextIOWrapper
的任何对象。
TextIOWrapper
中的_pyio.py
类在可读,可写或随机访问文件之间没有任何区别。两者都应该有效,或者两者都应该提高IOError
。
无论如何,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'模式来解决该问题。