[英]How to read from a file each time another another process updates it
I am working on my first application.我正在处理我的第一个应用程序。 In one window, I have a button that, when clicked, I want to execute a method from another module.在一个窗口中,我有一个按钮,单击该按钮后,我想从另一个模块执行一个方法。 This method takes an indeterminate amount of time to execute and depends on user input in the terminal.此方法需要不确定的时间来执行,并且取决于终端中的用户输入。 This method creates a file and repeatedly opens it, writes things to the file, and closes the file.此方法创建一个文件并重复打开它,将内容写入文件,然后关闭文件。 At the same time this is running I have a matplotlib graph widget in the window with a plot that I want to update each time something new is written to the file by reading and plotting data from the most recent line of the file.在运行的同时,我在窗口中有一个 matplotlib 图形小部件,其中包含一个绘图,每次通过读取和绘制文件最新行中的数据将新内容写入文件时,我都想更新该绘图。
As I understand it, nothing in my application will respond until the user input function finishes if I have it running in the main thread of my QT program.据我了解,如果我在 QT 程序的主线程中运行它,则在用户输入函数完成之前,我的应用程序中的任何内容都不会响应。 To address this I tried moving the execution of the user input method into a worker thread.为了解决这个问题,我尝试将用户输入法的执行移到工作线程中。 In the way I have done this I'm not convinced it is working.以我这样做的方式,我不相信它正在起作用。 As a test I tried making a QTimer that tried to read the file and plot it every second (with some added stuff to check if the file exists).作为测试,我尝试制作一个 QTimer,它尝试读取文件并每秒绘制一次(添加一些内容来检查文件是否存在)。 This prints that the file doesn't exist yet right until the long task, and then does nothing, until the long task is done and then starts reading and plotting the file every second.这将打印文件在长任务之前还不存在,然后什么都不做,直到长任务完成然后开始每秒读取和绘制文件。 I'm not sure if this means I'm not doing the threading properly or if something else is going on.我不确定这是否意味着我没有正确地进行线程处理,或者是否正在发生其他事情。
To check for changes to the file, I've tried using QFileSystemWatcher.为了检查文件的更改,我尝试使用 QFileSystemWatcher。 UPDATE: Right now, nothing happens while the userInputFunction() is running, but when it finishes I get "data/runName_Rec.txt dataFileCreated".更新:现在,当 userInputFunction() 运行时什么也没有发生,但是当它完成时我得到“data/runName_Rec.txt dataFileCreated”。 If I then manually edit the file in any way the plotting happens as it should.如果我然后以任何方式手动编辑文件,绘图就会发生。 But I still want to thread it correctly so that the watcher works while I'm running userInputFunction()但我仍然想正确地将其线程化,以便在我运行 userInputFunction() 时观察者工作
Here is a simplified sample of the relevant parts of my code.这是我的代码相关部分的简化示例。 Sorry for any bad style issues.对于任何糟糕的风格问题,我们深表歉意。
from PyQt5 import QtWidgets, uic, QtCore, QtGui
from pyqtgraph import PlotWidget
from PyQt5.QtCore import QObject, QThread, pyqtSignal
import pyqtgraph as pg
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QFileDialog, QMainWindow
import os
from os.path import exists
import csv
import numpy as np
import pandas as pd
import myModule
dirname = os.path.dirname(__file__)
class Worker(QObject):
finished = pyqtSignal()
def run(self,param1,param2):
"""Long-running task with user input from terminal."""
myModule.userInputFunction(param1,param2)
self.finished.emit()
class someWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(someWindow, self).__init__(*args, **kwargs)
#Load the UI Page
uic.loadUi('somewindow.ui', self)
self.directoryPath = "data"
self.fs_watcher = QtCore.QFileSystemWatcher()
self.fs_watcher.addPath(self.directoryPath)
self.fs_watcher.directoryChanged.connect(self.dataFileCreated)
self.StartScanButton.clicked.connect(self.startSliceScan)
self.EndScanButton.clicked.connect(self.endScan)
def dataFileCreated(self):
self.filePath = os.path.join(dirname, "data/"+ self.runNameBox.toPlainText()+"_Rec.txt")
print(self.filePath + " dataFileCreated")
self.fs_watcher.addPath(self.filePath)
self.fs_watcher.fileChanged.connect(self.update_graph)
def update_graph(self):
if exists(self.path):
print("file exists!")
#then read the filePath.txt and plots the data
else:
print("file doesn't exist yet")
def endScan(self):
#change some display things
def runLongTask(self):
# Step 2: Create a QThread object
self.thread = QThread()
# Step 3: Create a worker object
self.worker = Worker()
# Step 4: Move worker to the thread
self.worker.moveToThread(self.thread)
# Step 5: Connect signals and slots
self.thread.started.connect(self.worker.run(param1,param2))
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
# Step 6: Start the thread
self.thread.start()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = someWindow()
w.show()
sys.exit(app.exec_())
As you explained, when your program starts, the file in question does not exist yet.正如您所解释的,当您的程序启动时,相关文件尚不存在。
From the documentation of QFileSystemWatcher :从QFileSystemWatcher的文档中:
Adds path to the file system watcher if path exists.如果路径存在,则将路径添加到文件系统观察程序。 The path is not added if it does not exist, or if it is already being monitored by the file system watcher.如果该路径不存在,或者文件系统观察程序已对其进行监视,则不会添加该路径。
The solution to your problem is two-fold:解决您的问题有两个方面:
update_graph
method is already prepared for this dynamic as it checks for existence of your target file;您的update_graph
方法已经为此动态做好了准备,因为它会检查您的目标文件是否存在; so you can directly connect it to directoryChanged
as you did with fileChanged
.因此您可以像使用fileChanged
一样将其直接连接到directoryChanged
。update_graph
(it may appear redundant, but note, as in the quote above, redundantly adding a file is not a problem; also when you add the path at start you cover the case where the file is already there).只要文件在那里,为了获得文件未来任何更改的通知,将文件本身添加到观察者就像你已经做的那样,但这次也在update_graph
做(它可能看起来多余,但请注意,如上面的引用,多余地添加文件不是问题;同样,当您在开始时添加路径时,您涵盖了文件已经存在的情况)。addPath()
returns bool success.最后,请注意addPath()
返回 bool 成功。 So you should check the return value in your program.所以你应该检查程序中的返回值。 The reason for this behavior is that when you call addPath()
, the file or directory found at that path is directly added to the watcher (not the path pointing to it).这种行为的原因是当您调用addPath()
,在该路径找到的文件或目录会直接添加到观察者(而不是指向它的路径)。 So the notification only works during a file's (or directory's) lifetime.因此,通知仅在文件(或目录)的生命周期内有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.