ファイル編集システムを作成していますが、バイトベースではなくラインベースのtell()関数を作成したいと考えています。この関数は、open(file)呼び出しで「withloop」内で使用されます。この関数は、次のクラスの一部です。
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を返し、システムがファイルを反復処理する方法と関係があるということですが、私は問題を理解していません。助けてくれる人に感謝します。
古いバージョンのPython 3を使用しており、MacではなくLinuxを使用していますが、エラーに非常に近いものを再作成できました。
_IOError: telling position disabled by next() call
_
[〜#〜] io [〜#〜]エラーであり、[〜#〜] os [ 〜#〜]エラーですが、それ以外は同じです。奇妙なことに、私はあなたのopen('a+', ...)
を使用してそれを引き起こすことができませんでしたが、読み取りモードでファイルを開いたときだけです:open('r+', ...)
。
さらに厄介なのは、エラーが__io.TextIOWrapper
_、Pythonの__pyio.py
_ファイルで定義されているように見えるクラスから発生していることです。 。私は「現れる」ことを強調します。理由は次のとおりです。
そのファイルのTextIOWrapper
には、__telling
_のような属性があり、それ自体を__io.TextIOWrapper
_と呼んでいるオブジェクトにはアクセスできません。
__pyio.py
_のTextIOWrapper
クラスは、読み取り可能、書き込み可能、またはランダムアクセスファイルを区別しません。両方が機能するか、両方が同じIOError
を発生させる必要があります。
とにかく、__pyio.py
_ファイルで説明されている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
_をリセットするもう1つの方法は、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:alwaysが行番号と文字オフセットの両方を返すことを検討する必要があります。完全に異なる型を返すことができる関数は処理が困難です---呼び出し元が必要のない値を破棄する方がはるかに簡単です。
これが元のエラーであったかどうかはわかりませんが、次のようにファイルの行ごとの反復内で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()
はtellあなたになります。これは、バイト位置でのtellおよびseek作業としてASCIIファイルに対してのみ機能することに注意してください。行ベースでの作業は、文字列をバイトからユニコード文字列に変換するのは簡単です。