How to solve "OSError: telling position disabled by next() call"
How to solve "OSError: telling position disabled by next() call"
我正在创建一个文件编辑系统,我想创建一个基于行的 tell() 函数,而不是一个基于字节的函数。此函数将在 "with loop" 内部与 open(file) 调用一起使用。此函数是 class 的一部分,它具有:
self.f = open(self.file, 'a+')
# self.file is a string that has the filename in it
以下为原函数
(如果你想要行和字节 return,它也有一个字符设置):
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
我遇到的问题是这个 return 是一个 OSError,它与系统如何遍历文件有关,但我不明白这个问题。感谢任何能提供帮助的人。
我有一个旧版本的 Python 3,我在 Linux 而不是 Mac,但我能够重新创建一些非常接近你的错误的东西:
IOError: telling position disabled by next() call
一个 IO 错误,不是 OS 错误,但其他方面相同。奇怪的是,我无法使用您的 open('a+', ...)
导致它,但只有在以读取模式打开文件时才会导致它:open('r+', ...)
.
更令人困惑的是,错误来自 _io.TextIOWrapper
,一个 class 出现 被定义在 Python 的 _pyio.py
文件...我强调"appears",因为:
该文件中的 TextIOWrapper
具有类似 _telling
的属性,我无法在调用自身 _io.TextIOWrapper
的对象上访问这些属性。
_pyio.py
中的 TextIOWrapper
class 不区分可读、可写或随机访问文件。两者都应该起作用,或者两者都应该引发相同的 IOError
.
无论如何,_pyio.py
文件中描述的 TextIOWrapper
class 在迭代过程中禁用 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
至少在我的系统上,解决这个问题的方法是 在 TextIOWrapper
上调用 seek(0)
,这会将所有内容恢复到已知状态(并在讨价还价中成功调用 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:您应该考虑始终 return 同时考虑行号和字符偏移量。可以 return 完全不同类型的函数很难处理 --- 调用者更容易丢弃她或她不需要的值。
我不知道这是否是最初的错误,但如果您尝试在文件的 line-by-line 迭代中调用 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()
此问题的快速解决方法:
无论如何,当您从头开始遍历文件时,只需使用专用变量跟踪您的位置:
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 字符串很容易。
我有同样的错误:OSError: telling position disabled by next() call,并通过在打开文件时添加 'rb' 模式解决了这个问题。
我正在创建一个文件编辑系统,我想创建一个基于行的 tell() 函数,而不是一个基于字节的函数。此函数将在 "with loop" 内部与 open(file) 调用一起使用。此函数是 class 的一部分,它具有:
self.f = open(self.file, 'a+')
# self.file is a string that has the filename in it
以下为原函数 (如果你想要行和字节 return,它也有一个字符设置):
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
我遇到的问题是这个 return 是一个 OSError,它与系统如何遍历文件有关,但我不明白这个问题。感谢任何能提供帮助的人。
我有一个旧版本的 Python 3,我在 Linux 而不是 Mac,但我能够重新创建一些非常接近你的错误的东西:
IOError: telling position disabled by next() call
一个 IO 错误,不是 OS 错误,但其他方面相同。奇怪的是,我无法使用您的 open('a+', ...)
导致它,但只有在以读取模式打开文件时才会导致它:open('r+', ...)
.
更令人困惑的是,错误来自 _io.TextIOWrapper
,一个 class 出现 被定义在 Python 的 _pyio.py
文件...我强调"appears",因为:
该文件中的
TextIOWrapper
具有类似_telling
的属性,我无法在调用自身_io.TextIOWrapper
的对象上访问这些属性。_pyio.py
中的TextIOWrapper
class 不区分可读、可写或随机访问文件。两者都应该起作用,或者两者都应该引发相同的IOError
.
无论如何,_pyio.py
文件中描述的 TextIOWrapper
class 在迭代过程中禁用 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
至少在我的系统上,解决这个问题的方法是 在 TextIOWrapper
上调用 seek(0)
,这会将所有内容恢复到已知状态(并在讨价还价中成功调用 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:您应该考虑始终 return 同时考虑行号和字符偏移量。可以 return 完全不同类型的函数很难处理 --- 调用者更容易丢弃她或她不需要的值。
我不知道这是否是最初的错误,但如果您尝试在文件的 line-by-line 迭代中调用 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()
此问题的快速解决方法:
无论如何,当您从头开始遍历文件时,只需使用专用变量跟踪您的位置:
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 字符串很容易。
我有同样的错误:OSError: telling position disabled by next() call,并通过在打开文件时添加 'rb' 模式解决了这个问题。