web-dev-qa-db-ja.com

頻繁に更新されるファイルからの読み取り

現在、Linuxシステムのpythonでプログラムを作成しています。目的は、ログファイルを読み取り、特定の文字列を見つけたらbashコマンドを実行することです。ログファイルは常に書き込まれています。私の質問は:

Open()メソッドを使用してファイルを開くと、Pythonファイルオブジェクトは、実際のファイルが他のプログラムによって書き込まれるときに更新されますか、または一定の間隔でファイルを再度開く必要がありますか?

ありがとう

ジム

更新:これまでの回答をありがとう。おそらく、ファイルはJava EEアプリによって書き込まれているので、データが書き込まれるタイミングを制御することはできません。現在、ファイルを再オープンするプログラムがあります。 10秒ごとに、最後に読み取ったファイルのバイト位置から読み取ろうとします。現時点では、返された文字列を出力するだけです。ファイルを再度開く必要はありませんが、読み取りコマンドはJavaアプリによってファイルに書き込まれたデータに何らかの方法でアクセスできます。

#!/usr/bin/python
import time

fileBytePos = 0
while True:
    inFile = open('./server.log','r')
    inFile.seek(fileBytePos)
    data = inFile.read()
    print data
    fileBytePos = inFile.tell()
    print fileBytePos
    inFile.close()
    time.sleep(10)

Pyinotifyとジェネレーターに関するヒントをありがとう。より良い解決策として、これらを見ていきます。

43
JimS

David Beazleyの Pythonのジェネレータートリック 、特にパート5:無限データの処理を参照することをお勧めします。 Python tail -f logfileコマンドをリアルタイムで。

# follow.py
#
# Follow a file like tail -f.

import time
def follow(thefile):
    thefile.seek(0,2)
    while True:
        line = thefile.readline()
        if not line:
            time.sleep(0.1)
            continue
        yield line

if __== '__main__':
    logfile = open("run/foo/access-log","r")
    loglines = follow(logfile)
    for line in loglines:
        print line,
83
Jeff Bauer

「対話型セッションは1000語に相当します」

>>> f1 = open("bla.txt", "wt")
>>> f2 = open("bla.txt", "rt")
>>> f1.write("bleh")
>>> f2.read()
''
>>> f1.flush()
>>> f2.read()
'bleh'
>>> f1.write("blargh")
>>> f1.flush()
>>> f2.read()
'blargh'

言い換えれば、はい、単一の「オープン」で十分です。

17
jsbueno

以下は Jeff Bauer answerのわずかに修正されたバージョンで、ファイルの切り捨てに耐性があります。ファイルがlogrotateによって処理されている場合に非常に便利です。

import os
import time

def follow(name):
    current = open(name, "r")
    curino = os.fstat(current.fileno()).st_ino
    while True:
        while True:
            line = current.readline()
            if not line:
                break
            yield line

        try:
            if os.stat(name).st_ino != curino:
                new = open(name, "r")
                current.close()
                current = new
                curino = os.fstat(current.fileno()).st_ino
                continue
        except IOError:
            pass
        time.sleep(1)


if __== '__main__':
    fname = "test.log"
    for l in follow(fname):
        print "LINE: {}".format(l)
5

Linuxシステムをターゲットにしているため、 pyinotify を使用して、ファイルが変更されたときに通知できます。

this トリックもあります。それは使用しています file.seek 何をすべきか tail -fします。

3
nmichaels

Whileループで実行されているファイルを読み取るコードがある場合:

f = open('/tmp/workfile', 'r')
while(1):
    line = f.readline()
    if line.find("ONE") != -1:
        print "Got it"

また、別のプログラムから同じファイルに(追加モードで)書き込んでいます。ファイルに「ONE」が追加されるとすぐに、印刷されます。あなたがしたいことは何でもできます。つまり、定期的にファイルを再度開く必要はありません。

>>> f = open('/tmp/workfile', 'a')
>>> f.write("One\n")
>>> f.close()
>>> f = open('/tmp/workfile', 'a')
>>> f.write("ONE\n")
>>> f.close()
1
w00t

私はここでは専門家ではありませんが、何らかのオブザーバーパターンを使用してファイルを受動的に監視し、変更が発生したときにファイルを再度開くイベントを発生させる必要があると思います。これを実際に実装する方法については、私にはわかりません。

あなたが提案するようにopen()がリアルタイムでファイルを開くとは思いません。

1
Adam Pointer