作者:小 琛
欢迎转载,请标明出处
文章目录
场景
动态监控的好处:
- 无需关心具体的业务逻辑,只关注某个文件夹的情况,功能独立性高
- 配合 线程、信号绑定,不对主流程阻塞
实现流程
思路描述
- 单独抽离一个类,继承QThread,重写run()接口
- 在run()接口内,即线程启动时,初始化一个QFileSystemWatcher对象,并将需要监控的文件夹目录作为参数绑定
- 自定义信号,根据自身业务需求,对QFileSystemWatcher::QFileSystemWatcher以及QFileSystemWatcher::directoryChanged进行信号绑定
- 循环监控,直到外部信号终止
QFileSystemWatcher类
bool QFileSystemWatcher::addPath(const QString &file)
该接口,可以将一个路径作为动态检测的目标,保证传入的路径为可用的字符串,否则会失败
可以用QDir dir(folder_); if (!dir.exists(folder_))
QFileSystemWatcher::fileChanged(const QString &path, QPrivateSignal)
该信号,触发时候为被添加目录下的某个文件,被修改时,在实际使用中,可以拿到path即具体的路径
QFileSystemWatcher::directoryChanged(const QString &path, QPrivateSignal)
该信号,触发时候为被该目录下内容被改变,和fileChanged的区别是:当目录下有新增某个文件、删除某个文件时,触发信号。
QThread的联合使用
QThread的使用
-
创建一个 QThread 类的子类,用于实现具体的线程任务。这个子类需要重写 run() 函数,用于实现线程执行的代码。
-
在主线程中创建这个子类的对象,并调用 start() 函数启动线程。注意,这里只是调用了 start() 函数,实际的线程执行是在新的线程中完成的。
工具:QDir、QStringList、QFileInfoList
在操作文件、文件夹时,QT提供了非常方便的工具类;这里给出几个我用到例子,如果需要其它功能,可以查官网
QDir::exists() 判断路径是否存在;
QDir::mkpath()创建目录
得到某个目录下的所有.zip文件
QDir scriptDir(path);
auto newFileList = scriptDir.entryInfoList(QStringList() << "*.zip", QDir::Files);
例子:对文件夹新增、删除行为进行监控
#pragma once
#include <QObject>
#include <QThread>
#include <QMetaType>
class FolderMonitoring : public QThread {
Q_OBJECT
public:
enum ChangeType { Add, Delete};
FolderMonitoring (QObject* parent, QString& folder);
virtual ~FolderMonitoring () = default;
protected:
virtual void run() override;
signals:
void ChangeSignals(QFileInfoList list, ChangeType type);
void FileContentChange(const QString& file);
private slots:
void onFolderModified(const QString& path);
void onFileModified(const QString& path);
private:
QString folder_;
QFileInfoList fileInfoList_;
//QStringList fileList_;
};
Q_DECLARE_METATYPE(FolderMonitoring::ChangeType)
#include <QFile>
#include <QDir>
#include "FolderMonitoring.h"
#include "../../shell/utils/FileSystemWatcher.h"
FolderMonitoring::FolderMonitoring(QObject* parent, QString& folder) : QThread(parent), folder_(folder) {
// 获取文件夹中的所有文件
qRegisterMetaType<ScriptChangeType>("ScriptChangeType");
QDir scriptDir(folder);
fileInfoList_ = scriptDir.entryInfoList(QStringList() << "*.mmor", QDir::Files);
}
void FolderMonitoring::run() {
if (folder_.isEmpty()) return;
FileSystemWatcher* filesWatcher = new FileSystemWatcher();
connect(filesWatcher , &QFileSystemWatcher::directoryChanged, this, &FolderMonitoring::onFolderModified);
connect(filesWatcher , &QFileSystemWatcher::fileChanged,this, &FolderMonitoring::onFileModified);
// 文件夹不存在则创建
QDir dir(folder_);
if (!dir.exists(folder_)) {
dir.mkpath(".");
// todo: 处理失败
}
filesWatcher->addPath(folder_);
QThread::exec(); // 循环监控,直到外部信号终止
}
void FolderMonitoring::onFileModified(const QString& path) { emit FileContentChange(path); }
void FolderMonitoring::onFolderModified(const QString& path) {
QDir scriptDir(path);
auto newFileList = scriptDir.entryInfoList(QStringList() << "*.mmor", QDir::Files);
if (path == folder_) {
// 获取目录下的文件列表
QFileInfoList fileList = QDir(folder_).entryInfoList(QStringList() << "*.mmor", QDir::Files);
// 查找新增的.mmor文件
QFileInfoList addedFiles = fileList;
for (const auto& file : fileInfoList_) {
addedFiles.removeAll(file);
}
// 查找删除的.mmor文件
QFileInfoList removedFiles = fileInfoList_;
for (const auto& file : fileList) {
removedFiles.removeAll(file);
}
// 发射信号
if (!addedFiles.isEmpty()) {
emit scriptChangeSignals(addedFiles, ScriptAdd);
}
if (!removedFiles.isEmpty()) {
emit scriptChangeSignals(removedFiles, ScriptDelete);
}
// 更新文件列表
fileInfoList_ = fileList;
}
}