每次另一个进程更新文件时如何读取文件
How to read from a file each time another another process updates it
我正在处理我的第一个应用程序。在一个 window 中,我有一个按钮,单击该按钮时,我想从另一个模块执行一个方法。此方法的执行时间不确定,具体取决于用户在终端中的输入。此方法创建一个文件并重复打开它,向文件写入内容,然后关闭文件。同时这是 运行 我在 window 中有一个 matplotlib 图形小部件,其中有一个绘图,每次通过读取和绘制最新的数据向文件写入新内容时,我都想更新它文件的行。
据我了解,如果我在 QT 程序的主线程中 运行 有用户输入功能完成,我的应用程序中的任何内容都不会响应。为了解决这个问题,我尝试将用户输入方法的执行转移到工作线程中。在我这样做的方式中,我不相信它有效。作为测试,我尝试制作一个 QTimer,它试图每秒读取文件并绘制它(添加一些东西来检查文件是否存在)。这会打印出文件在长任务之前还不存在,然后什么都不做,直到长任务完成然后开始每秒读取和绘制文件。我不确定这是否意味着我没有正确进行穿线或者是否有其他问题。
为了检查文件的更改,我尝试使用 QFileSystemWatcher。更新:现在,当 userInputFunction() 为 运行 时没有任何反应,但当它完成时我得到“data/runName_Rec.txt dataFileCreated”。如果我随后以任何方式手动编辑文件,绘图就会按预期进行。但我仍然想正确地穿线它,以便观察者在我 运行 userInputFunction()
时工作
这是我的代码相关部分的简化示例。对于任何不良风格问题,我们深表歉意。
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_())
正如您所解释的,当您的程序启动时,相关文件尚不存在。
来自documentation of 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.
解决您问题的方法有两个:
- 要获得新创建文件的通知,请将 父目录(即您希望文件出现的目录)添加到您的观察者(在您的情况下,只需'.').当创建任何新文件时,您将收到通知(directoryChanged signal)。您的
update_graph
方法已经为此动态准备好,因为它会检查您的目标文件是否存在;因此您可以像 fileChanged
. 一样直接将其连接到 directoryChanged
- 一旦文件存在,为了得到文件未来任何更改的通知,像你已经做的那样将文件本身添加到观察者,但这次也在
update_graph
中做(它可能看起来多余,但请注意,如上面的引述所示,多余地添加文件不是问题;同样,当您在开始时添加路径时,您涵盖了文件已经存在的情况。
- 如果文件被删除,您将再次收到 directoryChanged 事件。删除文件的路径不需要去掉。
- 最后,请注意
addPath()
return 布尔成功。所以你应该检查程序中的 return 值。
此行为的原因是当您调用 addPath()
时,在该路径找到的文件或目录被直接添加到观察者(而不是指向它的路径)。因此通知仅在文件(或目录)的生命周期内有效。
我正在处理我的第一个应用程序。在一个 window 中,我有一个按钮,单击该按钮时,我想从另一个模块执行一个方法。此方法的执行时间不确定,具体取决于用户在终端中的输入。此方法创建一个文件并重复打开它,向文件写入内容,然后关闭文件。同时这是 运行 我在 window 中有一个 matplotlib 图形小部件,其中有一个绘图,每次通过读取和绘制最新的数据向文件写入新内容时,我都想更新它文件的行。
据我了解,如果我在 QT 程序的主线程中 运行 有用户输入功能完成,我的应用程序中的任何内容都不会响应。为了解决这个问题,我尝试将用户输入方法的执行转移到工作线程中。在我这样做的方式中,我不相信它有效。作为测试,我尝试制作一个 QTimer,它试图每秒读取文件并绘制它(添加一些东西来检查文件是否存在)。这会打印出文件在长任务之前还不存在,然后什么都不做,直到长任务完成然后开始每秒读取和绘制文件。我不确定这是否意味着我没有正确进行穿线或者是否有其他问题。
为了检查文件的更改,我尝试使用 QFileSystemWatcher。更新:现在,当 userInputFunction() 为 运行 时没有任何反应,但当它完成时我得到“data/runName_Rec.txt dataFileCreated”。如果我随后以任何方式手动编辑文件,绘图就会按预期进行。但我仍然想正确地穿线它,以便观察者在我 运行 userInputFunction()
时工作这是我的代码相关部分的简化示例。对于任何不良风格问题,我们深表歉意。
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_())
正如您所解释的,当您的程序启动时,相关文件尚不存在。
来自documentation of 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.
解决您问题的方法有两个:
- 要获得新创建文件的通知,请将 父目录(即您希望文件出现的目录)添加到您的观察者(在您的情况下,只需'.').当创建任何新文件时,您将收到通知(directoryChanged signal)。您的
update_graph
方法已经为此动态准备好,因为它会检查您的目标文件是否存在;因此您可以像fileChanged
. 一样直接将其连接到 - 一旦文件存在,为了得到文件未来任何更改的通知,像你已经做的那样将文件本身添加到观察者,但这次也在
update_graph
中做(它可能看起来多余,但请注意,如上面的引述所示,多余地添加文件不是问题;同样,当您在开始时添加路径时,您涵盖了文件已经存在的情况。 - 如果文件被删除,您将再次收到 directoryChanged 事件。删除文件的路径不需要去掉。
- 最后,请注意
addPath()
return 布尔成功。所以你应该检查程序中的 return 值。
directoryChanged
此行为的原因是当您调用 addPath()
时,在该路径找到的文件或目录被直接添加到观察者(而不是指向它的路径)。因此通知仅在文件(或目录)的生命周期内有效。