どのライン番号Aファイルポインターがオンになっているかを簡単に伝える方法はありますか?

StackOverflow https://stackoverflow.com/questions/6367051

  •  28-10-2019
  •  | 
  •  

質問

Python 2.5では、ファイルポインターを使用して、構造化されたテキストデータファイル(サイズで〜30 MB)を読んでいます。

fp = open('myfile.txt', 'r')
line = fp.readline()
# ... many other fp.readline() processing steps, which
# are used in different contexts to read the structures

しかし、その後、ファイルを解析している間、私はテキストエディターのファイルを調査できるように、行番号を報告したいという面白いことをヒットしました。使うことができます fp.tell() バイトオフセットがどこにあるかを教えてください(例: 16548974L)、しかし、これを行番号に翻訳するのに役立つ「fp.tell_line_number()」はありません。

テキストファイルのポインターがオンになっているライン番号を簡単に追跡および「伝える」ためのpython内蔵または拡張機能がありますか?

注:私はです 尋ねない 使用するには line_number += 1 私が呼ぶようにスタイルカウンター fp.readline() さまざまなコンテキストで、そのアプローチでは、コードの右コーナーにカウンターを挿入する価値があるよりも多くのデバッグが必要になります。

役に立ちましたか?

解決

この問題の典型的な解決策は、の既存のインスタンスをラップする新しいクラスを定義することです。 file, 、数値を自動的にカウントします。このようなもの(私の頭のすぐ外側、私はこれをテストしていません):

class FileLineWrapper(object):
    def __init__(self, f):
        self.f = f
        self.line = 0
    def close(self):
        return self.f.close()
    def readline(self):
        self.line += 1
        return self.f.readline()
    # to allow using in 'with' statements 
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

このように使用してください:

f = FileLineWrapper(open("myfile.txt", "r"))
f.readline()
print(f.line)

標準モジュールのように見えます fileinput ほぼ同じことをします(そして他のいくつかのことも同様です)。必要に応じて、代わりにそれを使用できます。

他のヒント

あなたが見つけるかもしれません fileinput モジュールが便利です。任意の数のファイルを繰り返すための一般化されたインターフェイスを提供します。ドキュメントからのいくつかの関連するハイライト:

fileinput.lineno()

読まれたばかりの行の累積線番号を返します。最初の行が読み取られる前に、0を返します。最後のファイルの最後の行が読み取られた後、その行の行番号を返します。

fileinput.filelineno()

現在のファイルの行番号を返します。最初の行が読み取られる前に、0を返します。最後のファイルの最後の行が読み取られた後、ファイル内のその行の行番号を返します。

次のコードには、ファイルを通過しながら、行番号(ポインターが現在オンになっている場所)を印刷します(「testfile」)

file=open("testfile", "r")
for line_no, line in enumerate(file):
    print line_no     # The content of the line is in variable 'line'
file.close()

出力:

1
2
3
...

あなたが望む方法ではなく、私はそうは思いません(あなたが返すPythonファイルハンドルの標準的な組み込み機能のように open).

ラインまたはラッパークラスの使用を読むときにライン番号を手動で追跡できない場合(ちなみに、GreghとSenderleによる優れた提案)、単に使用する必要があると思います。 fp.tell() フィギュアして、ファイルの開始に戻り、そこに着くまで読みます。

そうではありません それも エラー条件が水泳で働くすべてのものよりも可能性が低くなる可能性が低いと仮定しているため、悪い選択肢です。すべてが正常に機能する場合、影響はありません。

エラーがある場合は、ファイルを再実行する余分な努力があります。ファイルがある場合 大きい、 それはあなたの知覚されたパフォーマンスに影響を与える可能性があります - それが問題である場合はそれを考慮に入れる必要があります。

1つの方法は、ラインを反復し、すでに見られた行の数の明示的な数を保持することです。

>>> f=open('text.txt','r')
>>> from itertools import izip
>>> from itertools import count
>>> f=open('test.java','r')
>>> for line_no,line in izip(count(),f):
...     print line_no,line

次のコードは関数を作成します which_line_for_position(pos) それは 行の数 位置のために Pos, 、つまりです 行数 その中に位置に位置するキャラクターがあります Pos ファイル内。

この関数は、ファイルのポインターの現在の位置の値とは独立して、関数が呼び出される前のこのポインターの動きの歴史から、引数として任意の位置で使用できます。

したがって、この関数では、Greg Hewgillのソリューションの場合であるように、線の途切れない反復中に現在のラインの数を決定することに限定されません。

with open(filepath,'rb') as f:
    GIVE_NO_FOR_END = {}
    end = 0
    for i,line in enumerate(f):
        end += len(line)
        GIVE_NO_FOR_END[end] = i
    if line[-1]=='\n':
        GIVE_NO_FOR_END[end+1] = i+1
    end_positions = GIVE_NO_FOR_END.keys()
    end_positions.sort()

def Which_Line_for_Position(pos,
                            dic = GIVE_NO_FOR_END,
                            keys = end_positions,
                            kmax = end_positions[-1]):
    return dic[(k for k in keys if pos < k).next()] if pos<kmax else None

.

同じソリューションは、モジュールの助けを借りて書くことができます fileInput:

import fileinput

GIVE_NO_FOR_END = {}
end = 0
for line in fileinput.input(filepath,'rb'):
    end += len(line)
    GIVE_NO_FOR_END[end] = fileinput.filelineno()
if line[-1]=='\n':
    GIVE_NO_FOR_END[end+1] = fileinput.filelineno()+1
fileinput.close()

end_positions = GIVE_NO_FOR_END.keys()
end_positions.sort()

def Which_Line_for_Position(pos,
                            dic = GIVE_NO_FOR_END,
                            keys = end_positions,
                            kmax = end_positions[-1]):
    return dic[(k for k in keys if pos < k).next()] if pos<kmax else None

しかし、このソリューションにはいくつかの不便があります。

  • モジュールをインポートする必要があります fileInput
  • ファイルのすべてのコンテンツを削除します!!私のコードに何か問題があるに違いありませんが、私は知りません fileInput それを見つけるのに十分です。または、それは通常の動作ですか fileinput.input() 関数 ?
  • ファイルは、反復を起動する前に最初に完全に読み取られるようです。もしそうなら、非常に大きいファイルの場合、ファイルのサイズはRAMの容量を超える可能性があります。この点はわかりません。1,5GBのファイルでテストしようとしましたが、かなり長いので、今のところこのポイントを落としました。この点が正しければ、他のソリューションを使用するという議論を構成します enumerate()

.

例:

text = '''Harold Acton (1904–1994)
Gilbert Adair (born 1944)
Helen Adam (1909–1993)
Arthur Henry Adams (1872–1936)
Robert Adamson (1852–1902)
Fleur Adcock (born 1934)
Joseph Addison (1672–1719)
Mark Akenside (1721–1770)
James Alexander Allan (1889–1956)
Leslie Holdsworthy Allen (1879–1964)
William Allingham (1824/28-1889)
Kingsley Amis (1922–1995)
Ethel Anderson (1883–1958)
Bruce Andrews (born 1948)
Maya Angelou (born 1928)
Rae Armantrout (born 1947)
Simon Armitage (born 1963)
Matthew Arnold (1822–1888)
John Ashbery (born 1927)
Thomas Ashe (1836–1889)
Thea Astley (1925–2004)
Edwin Atherstone (1788–1872)'''


#with open('alao.txt','rb') as f:

f = text.splitlines(True)
# argument True in splitlines() makes the newlines kept

GIVE_NO_FOR_END = {}
end = 0
for i,line in enumerate(f):
    end += len(line)
    GIVE_NO_FOR_END[end] = i
if line[-1]=='\n':
    GIVE_NO_FOR_END[end+1] = i+1
end_positions = GIVE_NO_FOR_END.keys()
end_positions.sort()


print '\n'.join('line %-3s  ending at position %s' % (str(GIVE_NO_FOR_END[end]),str(end))
                for end in end_positions)

def Which_Line_for_Position(pos,
                            dic = GIVE_NO_FOR_END,
                            keys = end_positions,
                            kmax = end_positions[-1]):
    return dic[(k for k in keys if pos < k).next()] if pos<kmax else None

print
for x in (2,450,320,104,105,599,600):
    print 'pos=%-6s   line %s' % (x,Which_Line_for_Position(x))

結果

line 0    ending at position 25
line 1    ending at position 51
line 2    ending at position 74
line 3    ending at position 105
line 4    ending at position 132
line 5    ending at position 157
line 6    ending at position 184
line 7    ending at position 210
line 8    ending at position 244
line 9    ending at position 281
line 10   ending at position 314
line 11   ending at position 340
line 12   ending at position 367
line 13   ending at position 393
line 14   ending at position 418
line 15   ending at position 445
line 16   ending at position 472
line 17   ending at position 499
line 18   ending at position 524
line 19   ending at position 548
line 20   ending at position 572
line 21   ending at position 600

pos=2        line 0
pos=450      line 16
pos=320      line 11
pos=104      line 3
pos=105      line 4
pos=599      line 21
pos=600      line None

.

次に、機能を持つ which_line_for_position() 、現在の行の数を簡単に取得するのは簡単です:通り過ぎるだけ f.tell() 関数への議論として

しかし 警告: :使用するとき f.tell() ファイルのファイルのポインターの動きを実行すると、ファイルがバイナリモードで開かれることが絶対に必要です。 「RB」 また 「RB+」 また 「ab」 また ....

最近同様の問題をいじり、このクラスベースのソリューションを思いついた。

class TextFileProcessor(object):

    def __init__(self, path_to_file):
        self.print_line_mod_number = 0
        self.__path_to_file = path_to_file
        self.__line_number = 0

    def __printLineNumberMod(self):
        if self.print_line_mod_number != 0:
            if self.__line_number % self.print_line_mod_number == 0:
                print(self.__line_number)

    def processFile(self):
        with open(self.__path_to_file, 'r', encoding='utf-8') as text_file:
            for self.__line_number, line in enumerate(text_file, start=1):
                self.__printLineNumberMod()

                # do some stuff with line here.

をセットする print_line_mod_number あなたが記録したいケイデンスへの財産を呼び出してください processFile.

たとえば... 100行ごとにフィードバックが必要な場合は、このようになります。

tfp = TextFileProcessor('C:\\myfile.txt')
tfp.print_line_mod_number = 100
tfp.processFile()

コンソール出力はそうです

100
200
300
400
etc...

について @eyquemによる解決策, 、使用することをお勧めします mode='r' FileInputモジュールと fileinput.lineno() オプションとそれは私のために働いています。

コードにこれらのオプションを実装している方法は次のとおりです。

    table=fileinput.input('largefile.txt',mode="r")
    if fileinput.lineno() >= stop : # you can disregard the IF condition but I am posting to illustrate the approach from my code.
           temp_out.close()
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top