【问题标题】:Monitoring if a file stopped writing in python监控文件是否停止在 python 中写入
【发布时间】:2015-09-30 06:19:27
【问题描述】:

我有一个程序每秒都在写入文件。文件写入发生在与 UI 平行的线程中。由于某些硬件问题,它有时会停止写入一天。我想检查文件是否停止写入,如果没有更新则重新启动程序。我想检查文件的时间戳,看看它是否没有更新(并且不想进入看门狗等,因为如果文件停止写入,我只需要。)

try:
    if time.time()>(os.stat(filename).st_mtime+2):
        raise ValueError("Yikes! Spike")
except ValueError:
    with open('errors.log','a') as log:
        log.write('Spike occured at '+ time.strftime(
        "%H:%M:%S")+' on '+datetime.date.today().strftime('%d/%m/%Y')+'\n')
        log.close()
    restart_program()

这个块每秒运行一次。但这适得其反,当应用程序关闭以重新启动时,它每秒都会关闭并且不会再次启动。我每秒都会记录一次异常消息。我尝试增加时差,但没有帮助。

接下来我尝试了

ftimestamp = os.stat(filename).st_mtime
try:
    if os.stat(filename).st_mtime>=ftimestamp:
        ftimestamp = time.time()
        print "ftimestamp updated and all is well"
    else:
        ftimestamp = os.stat(filename).st_mtime
        raise ValueError("Yikes! Spike!")
        print "file time is behind"
except ValueError:
    with open('errors.log','a') as log:
        log.write('Spike occured at '+ time.strftime(
        "%H:%M:%S")+' on '+datetime.date.today().strftime('%d/%m/%Y')+'\n')
        log.close()
    restart_program()

我尝试将变量“ftimestamp”更新为当前时间“time.time()”,因为下一次比较仅在一秒后发生,并且我希望文件时间高于上一次比较。 (该块通过 wx.CallLater 函数每秒运行一次)。

我的程序仍然失败......而且我无法理解我哪里出错了......请有人帮忙!或者有没有办法简单地检查文件是否停止写入?

【问题讨论】:

  • EOF错误!你试过了吗
  • 写入过程是否每秒刷新一次输出?
  • 只检查进程是否仍然存在可能更简单。为此,您可以使用信号 0 执行 kill(pid,0)
  • @therealprashant 从技术上讲,文件在写入时始终处于打开状态。我不确定 EOFerror 是否可以在这里提供帮助...
  • @meuh 是的!每次写入时(每秒)它都会刷新输出,您在说哪个进程?是否有单独的文件写入过程?我也在检查文件写入线程是否还活着 BTW

标签: python file timestamp


【解决方案1】:

我们可以尝试通过执行以下操作来检查文件大小的变化作为可能的解决方案:

import os
from time import sleep
# other imports

while True:
    file1 = os.stat('file.txt') # initial file size
    file1_size = file1.st_size
 
    # your script here that collects and writes data (increase file size)
    sleep(1)
    file2 = os.stat('file.txt') # updated file size
    file2_size = file2.st_size
    comp = file2_size - file1_size # compares sizes
    if comp == 0:
        restart_program()
    else:
        sleep(5)

您可能需要相应地调整sleep() 函数,这些只是我正在使用的估计值,因为我无法测试您的实际代码。最后,这是一个无限循环,只要您希望脚本继续编写,它就会一直运行。

另一种解决方案是将您的代码更新为:

import os
import sys
from time import sleep
# other imports

while True:
    file1 = os.stat('file.txt') # initial file size
    file1_size = file1.st_size
 
    # your script here that collects and writes data (increase file size)
    sleep(1)
    file2 = os.stat('file.txt') # updated file size
    file2_size = file2.st_size
    comp = file2_size - file1_size # compares sizes
    if comp == 0:
        sys.exit
    else:
        sleep(5)

然后使用辅助程序来运行您的脚本:

import os
from time import sleep, strftime

while True:
    print(strftime("%H:%M:%S"), "Starting"))
    system('main.py') # this is another infinite loop that will keep your script running
    print(strftime("%H:%M:%S"), "Crashed"))
    sleep(5)

【讨论】:

  • 我没有在我的脚本中使用 sleep 的奢侈,因为我的 UI 会非常滞后(使用 wx.CallLater 函数来设置一些更新的文本字段!)。最后一个解决方案似乎很有趣。在无限循环脚本中运行无限循环脚本有多安全?系统密集程度如何?让我测试一下,然后回复你。感谢您的努力。
  • 嗯.. 你把它无限循环放入无限循环 的方式非常危险,但是 在这种情况下它们是可控的。只要main.py 运行良好(这是我们想要的),“辅助程序”就处于无限循环中,对于第二个文件,它处于无限循环中,直到文件大小没有改变,因此它们都受到控制。辅助程序,作为主循环,如果终止也将终止所有其他的。
  • 第一个解决方案对我不起作用,因为 UI 挂起,第二个解决方案不起作用,因为文件在线程中更新,而不是您假设的顺序。尝试了其他使用文件大小的方法也徒劳无功。我尝试的最后一个,但问题是它可以很好地重新启动应用程序,但会无限期地继续重新启动。看起来时间戳异常无限期地发生并继续崩溃。但再次感谢您的努力。
【解决方案2】:

要确定文件是否在 GUI 程序中按时更改,您可以使用事件循环的标准工具,每隔间隔秒运行一个函数,例如,tkinter 中的操作方法如下:

#!/usr/bin/env python3
import logging
import os
import sys
import tkinter
from datetime import datetime
from time import monotonic as timer, localtime

path = sys.argv[1]
interval = 120 # check every 2 minutes

def check(last=[None]):
    mtime = os.path.getmtime(path) # or os.path.getsize(path)
    logging.debug("mtime %s", datetime.fromtimestamp(mtime))
    if last[0] == mtime: #NOTE: it is always False on the first run
        logging.error("file metadata hasn't been updated, exiting..")
        root.destroy() # exit GUI
    else: # schedule the next run
        last[0] = mtime
        root.after(round(1000 * (interval - timer() % interval)), check)


logging.basicConfig(level=logging.DEBUG,
                    filename=os.path.splitext(__file__)[0] + ".log",
                    format="%(asctime)-15s %(message)s", datefmt="%F %T")
root = tkinter.Tk()
root.withdraw() # hide GUI
root.after(round(1000 * (interval - timer() % interval)), check) # start on boundary
root.mainloop()

您可以使用 supervisord、systemd 或 upstart 等来自动重生您的脚本。

How to run a function periodically in python

【讨论】:

  • 感谢您的代码。我在 wxpython 中使用与 root.after() 类似的函数,称为 wx.CallLater(1,some_function())。由于我的应用程序都是用 wx 编写的,所以现在不能回去了!感谢您的努力...
  • @RohinKumar:tkinter 只是一个例子。 “使用标准工具”建议您应该在您的 GUI 框架中使用更合适的工具 (wx)。如果是wx.CallLater(),则使用wx.CallLater()——程序结构(算法)不会改变。如果您不想(不能)使用watchdog or its analogs with a push interface,那么对计时器进行轮询是一个合理的选择。
  • 是的,您的算法也可以与 CallLater 一起使用。我的程序遇到了更多问题。稍作修改,我想我就可以工作了。
  • @RohinKumar:注意:您不需要使用我回答中的算法调用touch(filename)last[0] == mtime 第一次运行check()总是 false即,重新启动后文件更改的时间超过interval秒(如果您想在此处添加特殊的首次操作,您可以通过last[0] is None条件检测第一次运行,例如,您可以将interval加倍第一次运行)。
  • 我同意!没看到...谢谢!
【解决方案3】:

最后,在修改了基于时间戳的选项之后,以下似乎对我有用。

try:
    if time.time()-os.stat(filename).st_mtime>6:
        touch(filename)
        raise ValueError("Yikes! Spike")
except ValueError:
    with open('errors.log','a') as log:
        log.write('Spike/App restarting occured at '+ time.strftime(
                "%H:%M:%S")+' on '+datetime.date.today().strftime('%d/%m/%Y')+'\n')
        log.close()
    restart_program()

之前的问题是它会检测到文件在给定的时间间隔内停止写入并继续满足相同的要求。

time.time()-os.stat(filename).st_mtime>6 

但是一旦满足这个条件,除非文件时间戳被更新,否则它会继续满足这个条件并且会不断重启程序。现在在我的解决方案中,我“触摸”了一次文件 (touch used from here),条件得到满足,现在它可以按预期工作了。

感谢大家的投入。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-12-19
  • 2015-11-14
  • 2013-08-11
  • 1970-01-01
  • 2021-08-18
  • 2014-09-16
  • 2019-12-29
  • 1970-01-01
相关资源
最近更新 更多