方法摘要:监控文件状态是否发生变化(创建/删除/修改),如发生变化释放Signal
实现思路:创建一个signal;创建一个列表,里面包含一个或多个文件路径;并启动一个timer,将timeout关联到一个slot,在slot中顺序检查列表中的这些文件是否发生了改变(创建/删除/修改),如果发生变化,则emit signal、并停止此次检查(所以fileChanged信号是关于列表中第一个发生变化的路径的。
如何使用:①利用addPath添加要监控的路径,②将你的slot与fileChanged信号connect,③signal提供两个信息:发生改变的路径,和改变的类型、时间
一些说明:
- 为什么不用QFileSystemWatcher:①如果在监视开始之前文件不存在,那么后来文件创建之后也不能对其进行监视(个人猜测是因为由于不存在直接不能添加到监视列表);②如果文件中途被删掉了,那么即便再创建了也没法继续监视了
- 目前python水平较low,所以上面所说的“列表”用了比较low的实现方式:一个数组是文件名、一个数组是文件是否存在的标志、另加一个计数。
- win10测试,测试了对文件的监控,但是没有测试对文件夹的监控;
- 可能的bug:测试程序偶有出现卡死的现象,尚不知为何。
- fileChanged信号检测到第一个改变的path之后就发出了,后面再有修改并不做监测。
- 适用常见情况:修改、创建、删除、删除了又重新创建了
- 必要的改进:addPath中检查是否已经存在于列表中、避免重复添加
附1/2:MyWatcher.py
import os, sys, time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
def timestr(t):
return time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(t))
class MyFileSystemWatcher(QObject):
fileChanged = pyqtSignal(str, str) # path, information
def __init__(self):
super().__init__()
self.pathList = ['NULL']
self.pathFlag = [0]
self.pathNum = 1
self.timer = QTimer()
self.timerInterval = 0.1 # regard it as a delay, 0.1 means 100ms
self.timer.start(self.timerInterval*1000)
self.timer.timeout.connect(self.slot_timeout_checkChange)
def addPath(self,path):
self.pathList.append(path)
self.pathNum = self.pathNum + 1
if os.path.exists(path):
self.pathFlag.append(1)
else:
self.pathFlag.append(0)
def slot_timeout_checkChange(self):
for i in range(self.pathNum):
path = self.pathList[i]
timeCurrent = time.time()
if self.pathFlag[i]: # exits before this check (may or may not exist now!)
if os.path.exists(path): # still exists but has been modified (do nothing if still exists unmodified)
timeModify = os.stat(path).st_mtime; # not self.pathModifiedTime[i] since modification may not be detected last time
if timeCurrent - timeModify < self.timerInterval :
self.fileChanged.emit( path, 'modified at '+timestr(timeModify) )
break
else: # no more exist, so it was deleted at timeCurrent-timerInterval or later. Since timerInterval<=1 & the samllest time unit is second, it can be regraded that it is deleted now
self.fileChanged.emit(path,'removed at ' + timestr(timeCurrent) )
self.pathFlag[i] = 0
break
else: # does not exist before this check (may or may not exist now!)
if os.path.exists(path): # now exists, so it is just created
timeModify = os.stat(path).st_mtime;
self.fileChanged.emit(path, 'created at ' + timestr(timeModify) )
self.pathFlag[i] = 1
break
附2/2:测试
import os, sys, time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from MyWatcher import *
ftxt = 'test_file.txt'
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.filewatcher = MyFileSystemWatcher()
self.filewatcher.addPath(ftxt)
self.label = QLabel('Content of {0}:'.format(ftxt))
self.textedit = QTextEdit()
self.slot_load_show_text() #init
self.filewatcher.fileChanged.connect(self.slot_fileChanged_update)
layout_vbox = QVBoxLayout()
layout_vbox.addWidget(self.label)
layout_vbox.addWidget(self.textedit)
self.setLayout(layout_vbox)
self.setWindowTitle('Mainwindow')
self.setGeometry(300,300,500,200)
self.show()
def slot_load_show_text(self):
if os.path.exists(ftxt):
time_modified = os.stat(ftxt).st_mtime
time_modified_str=time.strftime( '%Y-%m-%d %H:%M:%S',time.localtime(time_modified) )
self.textedit.setText(open(ftxt,'r').read())
self.textedit.append('*** last modified at {0} ***'.format(time_modified_str) )
else:
self.textedit.setText('** {0} does not exist **'.format(ftxt))
def slot_fileChanged_update(self,pathModified,infoModify):
self.slot_load_show_text()
print(pathModified, infoModify)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainwindow = MainWindow()
sys.exit(app.exec_())