从经常更新的文件中读取

问题描述:

我目前正在用Python在Python系统上编写程序。目标是读取日志文件并在查找特定字符串时执行bash命令。日志文件正在不断被另一个程序写入。我的问题是:从经常更新的文件中读取

如果我打开文件使用open()方法将我的Python文件对象更新为实际文件被其他程序写入或我将不得不重新打开文件定时?

感谢

吉姆

UPDATE: 感谢迄今答案。我也许应该提到该文件是由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和发电机的提示。我会看看这些更好的解决方案。

我会建议看看David Beazley的Generator Tricks for Python,尤其是第5部分:处理无限数据。它将实时处理相当于tail -f logfile命令的Python。

# 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, 
+2

这个答案应该被接受 – Quinma 2013-11-20 19:46:15

+0

如果答案在OP代码的条款中包含的代码示例,我会给予好评。 – 2014-05-01 20:25:14

+0

@ Chiel92:David Beazley网站添加的代码示例 – 2014-05-02 14:07:39

我不是这里的专家,但我认为你将不得不使用某种观察者模式来被动地观看文件,然后在发生更改时触发重新打开文件的事件。至于如何实际执行这个,我不知道。

我不认为open()会按照您的建议实时打开文件。

由于您的目标是Linux系统,因此您可以使用pyinotify在文件更改时通知您。

还有this技巧,它可能适合你。它使用file.seek来执行tail -f所做的事情。

如果你的代码读取while循环运行文件:

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

,并正在从另一个程序写入到同一文件(追加模式)。只要“文件”附加在文件中,您将获得打印。你可以采取任何你想采取的行动。总之,您不必定期重新打开文件。

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

这个答案也是错误的,写入可能会分裂成'ON'和'E \ n'这将导致两条线都不匹配。 – Fabian 2014-07-18 13:27:36

“的互动环节是值得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' 

换句话说 - 是的,一个 “开放” 就行了。

+0

这很有趣! – 2011-03-24 15:57:37

这是一个略有修改的版本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)