从频繁更新的文件中读取

74 投票
9 回答
85502 浏览
提问于 2025-04-16 14:20

我现在在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和生成器的建议。我会看看这些,寻找更好的解决方案。

9 个回答

14

这是对Jeff Bauer回答的一个稍微修改过的版本,它能够防止文件被截断。如果你的文件正在被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 __name__ == '__main__':
    fname = "test.log"
    for l in follow(fname):
        print "LINE: {}".format(l)
27

“一次互动的交流胜过千言万语。”

>>> 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'

换句话说 - 是的,打开一次就够了。

127

我建议你看看David Beazley的Python中的生成器技巧,特别是第5部分:处理无限数据。这部分会教你如何在实时处理中实现类似于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 __name__ == '__main__':
    logfile = open("run/foo/access-log","r")
    loglines = follow(logfile)
    for line in loglines:
        print line,

撰写回答