19

重複の可能性:
Python でファイルの最後の n 行を取得する、tail と同様に Python
を使用してファイルを逆順に読み取る

サイズが約 15GB のファイルがあります。これは、出力を分析することになっているログ ファイルです。私はすでに、数行のロギングで、同様の非常に小さいファイルの基本的な解析を行いました。文字列の解析は問題ではありません。問題は、巨大なファイルとそれに含まれる冗長データの量です。

基本的に、私は言うことができるpythonスクリプトを作成しようとしています。たとえば、ファイルの最後の 5000 行を教えてください。これも引数の基本的な処理であり、特別なことは何もありません。私はそれを行うことができます。

しかし、ファイルの最後から指定した行数だけを読み取るようにファイルリーダーを定義または指示するにはどうすればよいですか? 私はそれらに興味がないので、ファイルの先頭にある膨大な量の行をスキップしようとしいます。正直に言うと、txtファイルから約15GBの行を読み取るには時間がかかりすぎます。ファイルの最後から読み取りを開始する方法はありますか? それは意味がありますか?

要するに、15 GB のファイルを 1 行ずつ読み取るには時間がかかりすぎるという問題です。したがって、最初はすでに冗長なデータ (少なくとも私にとっては冗長) をスキップし、読み取りたいファイルの終わりから行数だけを読み取りたいと考えています。

明白な答えは、手動でファイルから別のファイルにN行分をコピーすることですが、Pythonでファイルの最後からN行分を読み取るためだけにこれを半自動魔法で行う方法はありますか?

4

4 に答える 4

21

これを unix にファームします:

import os
os.popen('tail -n 1000 filepath').read()

stderr (およびその他の機能) にアクセスできるようにする必要がある場合は、os.popen の代わりに subprocess.Popen を使用します。

于 2012-09-06T06:58:25.543 に答える
13

ファイルの最後までシークし、行を読み取るのに十分な改行が見つかるまで、行を数えながら、最後からブロック単位でいくつかのチャンクを読み取る必要がありますn

基本的に、テールの単純な形式を再実装しています。

これを行う簡単にテストされたコードを次に示します。

import os, errno

def lastlines(hugefile, n, bsize=2048):
    # get newlines type, open in universal mode to find it
    with open(hugefile, 'rU') as hfile:
        if not hfile.readline():
            return  # empty, no point
        sep = hfile.newlines  # After reading a line, python gives us this
    assert isinstance(sep, str), 'multiple newline types found, aborting'

    # find a suitable seek position in binary mode
    with open(hugefile, 'rb') as hfile:
        hfile.seek(0, os.SEEK_END)
        linecount = 0
        pos = 0

        while linecount <= n + 1:
            # read at least n lines + 1 more; we need to skip a partial line later on
            try:
                hfile.seek(-bsize, os.SEEK_CUR)           # go backwards
                linecount += hfile.read(bsize).count(sep) # count newlines
                hfile.seek(-bsize, os.SEEK_CUR)           # go back again
            except IOError, e:
                if e.errno == errno.EINVAL:
                    # Attempted to seek past the start, can't go further
                    bsize = hfile.tell()
                    hfile.seek(0, os.SEEK_SET)
                    pos = 0
                    linecount += hfile.read(bsize).count(sep)
                    break
                raise  # Some other I/O exception, re-raise
            pos = hfile.tell()

    # Re-open in text mode
    with open(hugefile, 'r') as hfile:
        hfile.seek(pos, os.SEEK_SET)  # our file position from above

        for line in hfile:
            # We've located n lines *or more*, so skip if needed
            if linecount > n:
                linecount -= 1
                continue
            # The rest we yield
            yield line
于 2012-09-06T07:32:30.693 に答える
-1

私は「テール」ソリューションを好みますが、1行あたりの最大文字数がわかっている場合は、ファイルのサイズを取得し、ファイルハンドラーを開いて推定数で「シーク」メソッドを使用することにより、別の可能なソリューションを実装できますあなたが探している文字の。

この最終的なコードは次のようになります。なぜ私がテール ソリューションを好むのかを説明するためです :) がんばってください!

MAX_CHARS_PER_LINE = 80
size_of_file = os.path.getsize('15gbfile.txt')
file_handler = file.open('15gbfile.txt', "rb")
seek_index = size_of_file - (number_of_requested_lines * MAX_CHARS_PER_LINE)
file_handler.seek(seek_index)
buffer = file_handler.read()

読み取ったバッファの改行を分析することで、このコードを改善できます。頑張ってください (そして、tail ソリューションを使用する必要があります ;-) すべての OS で tail を取得できると確信しています)

于 2012-09-06T07:25:27.660 に答える
-2

この時点で推奨される方法は、ジョブにUNIXのテールを使用し、Pythonを変更してstd入力を介した入力を受け入れることでした。

tail hugefile.txt -n1000 | python magic.py

それはセクシーなことではありませんが、少なくともそれは仕事の世話をします。大きなファイルは処理するには負担が大きすぎることがわかりました。少なくとも私のPythonスキルについては。したがって、ファイルサイズを縮小するために、nixマジックのピンチを追加するだけの方がはるかに簡単でした。尻尾は私にとって新しいものだったので。何かを学び、端末を再び有利に使用する別の方法を見つけました。みんなありがとう。

于 2012-09-06T06:49:19.357 に答える