32

私は今、次を使用してテキストファイル内の行をカウントする非常に単純なスクリプトを持っていますenumerate():

i = 0
f = open("C:/Users/guest/Desktop/file.log", "r")
for i, line in enumerate(f):
      pass
print i + 1
f.close()

これには、約 3,000 万行の 15 GB のログ ファイルを処理するのに約 3 分半かかります。これらは毎日のログであり、毎月の分析を行いたいため、これを 2 分以内で取得できれば素晴らしいことです。そのため、コードは最大 15 GB のログを 30 個処理する必要があり、1 時間半以上かかる可能性があります。 、サーバーの時間とメモリの負荷を最小限に抑えたいと考えています。

また、適切な近似/推定方法で解決しますが、約4シグフィグの精度である必要があります...

ありがとうございました!

4

5 に答える 5

40

Ignacio の答えは正しいですが、32 ビット プロセスを使用している場合は失敗する可能性があります。

\nしかし、ファイルをブロック単位で読み取り、各ブロックの文字数をカウントすると便利な場合があります。

def blocks(files, size=65536):
    while True:
        b = files.read(size)
        if not b: break
        yield b

with open("file", "r") as f:
    print sum(bl.count("\n") for bl in blocks(f))

あなたの仕事をします。

ファイルをバイナリとして開かないことに注意して\r\nください\n

Python 3 の場合、およびより堅牢にするために、あらゆる種類の文字を含むファイルを読み取るために:

def blocks(files, size=65536):
    while True:
        b = files.read(size)
        if not b: break
        yield b

with open("file", "r",encoding="utf-8",errors='ignore') as f:
    print (sum(bl.count("\n") for bl in blocks(f)))
于 2012-03-09T09:24:14.943 に答える
20

私はそれが少し不公平であることを知っていますが、あなたはこれを行うことができます

int(subprocess.check_output("wc -l C:\\alarm.bat").split()[0])

Windowsを使用している場合は、Coreutilsを確認してください。

于 2012-03-09T09:31:00.760 に答える
15

高速な 1 行のソリューションは次のとおりです。

sum(1 for i in open(file_path, 'rb'))

任意のサイズのファイルで動作するはずです。

于 2016-06-02T19:56:20.733 に答える
3

ファイルをmmapし、改行を数えます。

于 2012-03-09T05:09:10.890 に答える
2

gl の答えを拡張し、マルチプロセッシング Python モジュールを使用して彼/彼女のコードを実行して、カウントを高速化します。

def blocks(f, cut, size=64*1024): # 65536
    start, chunk =cut
    iter=0
    read_size=int(size)
    _break =False
    while not _break:
        if _break: break
        if f.tell()+size>start+chunk:
            read_size=int(start+chunk- f.tell() )
            _break=True
        b = f.read(read_size)
        iter +=1
        if not b: break
        yield b


def get_chunk_line_count(data):
    fn,  chunk_id, cut = data
    start, chunk =cut
    cnt =0
    last_bl=None

    with open(fn, "r") as f:
        if 0:
            f.seek(start)
            bl = f.read(chunk)
            cnt= bl.count('\n')
        else:
            f.seek(start)
            for i, bl  in enumerate(blocks(f,cut)):
                cnt +=  bl.count('\n')
                last_bl=bl

        if not last_bl.endswith('\n'):
            cnt -=1

        return cnt
....
pool = multiprocessing.Pool(processes=pool_size,
                            initializer=start_process,
                            )
pool_outputs = pool.map(get_chunk_line_count, inputs)
pool.close() # no more tasks
pool.join() 

これにより、計数性能が 20 倍向上します。それをスクリプトにラップして、Github に置きました。

于 2016-12-06T21:21:42.170 に答える