Qt文件系统源码分析—第八篇QFileSystemWatcher

深度

本文主要分析Windows平台,Mac、Linux暂不涉及

本文只分析到Win32 API/Windows Com组件/STL库函数层次,再下层代码不做探究

本文QT版本5.15.2

类关系图

QTemporaryFile继承QFile

QFile、QSaveFile继承QFileDevice

QFileDevice继承QIODevice

QIODevice、QFileSystemWatcher继承QObject

QLockFile、QFileInfo、QDir、QFileSelector无任何继承关系

QObject中有一指向QObjectData指针d_ptr。d_ptr是保护成员变量,这意味着每个子类可以修改d_ptr内容。在QObject中d_ptr指向QObjectPrivate,

QIODevice中d_ptr指向QIODevicePrivate

QFileDevice中d_ptr指向QFileDevicePrivate

QFile中d_ptr指向QFilePrivate

QTemporaryFile中d_ptr指向QTemporaryFilePrivate

QFileInfo、QDir、QLockFile不继承QObject,因此没有指向QObjectData指针d_ptr。但是各自同样声明了d_ptr变量指向各自的private类

QFileInfo中d_ptr指向QFileInfoPrivate

QDir中d_ptr指向QDirPrivate

QLockFile中d_ptr指向QLockFilePrivate

启发:

这种Private类书写方式适合场景是导出接口稳定、不想公开内部实现细节、内部能够灵活修改

可以用在付费插件、软件逆向等使用场景

QFileSystemWatcher

作用

监视文件夹或者文件

原理

在内部创建监视线程,等Windows操作系统发送目标变更事件后,读取事件解析后发出文件删除、更改等信号。

使用示例

XFileSystemWatcher.h:

#pragma once

#include <QObject>

#include <QMap>

#include <QFileSystemWatcher>

class XFileSystemWatcher : public QObject

{

Q_OBJECT

public:

static void addWatchPath(QString path);

static void clean();

public slots:

// 目录更新时调用,path是监控的路径

void directoryUpdated(const QString& path);

// 文件被修改时调用,path是监控的路径

void fileUpdated(const QString& path);

private:

explicit XFileSystemWatcher(QObject* parent = 0);

private:

static XFileSystemWatcher* m_pInstance;

QFileSystemWatcher* m_pSystemWatcher;

// 当前每个监控的内容目录列表

QMap<QString, QStringList> m_currentContentsMap;

};

XFileSystemWatcher.cpp

#include <QDir>

#include <QFileInfo>

#include <qDebug>

#include <qglobalstatic>

#include "XFileSystemWatcher.h"

XFileSystemWatcher* XFileSystemWatcher::m_pInstance = NULL;

//Q_GLOBAL_STATIC(QFileSystemWatcher, hxTest);

XFileSystemWatcher::XFileSystemWatcher(QObject* parent)

: QObject(parent)

{}

// 监控文件或目录

void XFileSystemWatcher::addWatchPath(QString path)

{

qDebug() << QString("Add to watch: %1").arg(path);

if (m_pInstance == NULL)

{

m_pInstance = new XFileSystemWatcher();

m_pInstance->m_pSystemWatcher = new QFileSystemWatcher();

// 连接QFileSystemWatcher的directoryChanged和fileChanged信号到相应的槽

connect(m_pInstance->m_pSystemWatcher, SIGNAL(directoryChanged(QString)), m_pInstance, SLOT(directoryUpdated(QString)));

connect(m_pInstance->m_pSystemWatcher, SIGNAL(fileChanged(QString)), m_pInstance, SLOT(fileUpdated(QString)));

}

// 添加监控路径

m_pInstance->m_pSystemWatcher->addPath(path);

// 如果添加路径是一个目录,保存当前内容列表

QFileInfo file(path);

if (file.isDir())

{

const QDir dirw(path);

m_pInstance->m_currentContentsMap[path] = dirw.entryList(QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Files, QDir::DirsFirst);

}

}

void XFileSystemWatcher::clean()

{

delete m_pInstance->m_pSystemWatcher;

m_pInstance->m_pSystemWatcher = new QFileSystemWatcher();

}

// 只要任何监控的目录更新(添加、删除、重命名),就会调用。

void XFileSystemWatcher::directoryUpdated(const QString& path)

{

qDebug() << QString("Directory updated: %1").arg(path);

// 比较最新的内容和保存的内容找出区别(变化)

QStringList currEntryList = m_currentContentsMap[path];

const QDir dir(path);

QStringList newEntryList = dir.entryList(QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Files, QDir::DirsFirst);

QSet<QString> newDirSet = QSet<QString>::fromList(newEntryList);

QSet<QString> currentDirSet = QSet<QString>::fromList(currEntryList);

// 添加了文件

QSet<QString> newFiles = newDirSet - currentDirSet;

QStringList newFile = newFiles.toList();

// 文件已被移除

QSet<QString> deletedFiles = currentDirSet - newDirSet;

QStringList deleteFile = deletedFiles.toList();

// 更新当前设置

m_currentContentsMap[path] = newEntryList;

if (!newFile.isEmpty() && !deleteFile.isEmpty())

{

// 文件/目录重命名

if ((newFile.count() == 1) && (deleteFile.count() == 1))

{

qDebug() << QString("File Renamed from %1 to %2").arg(deleteFile.first()).arg(newFile.first());

}

}

else

{

// 添加新文件/目录至Dir

if (!newFile.isEmpty())

{

qDebug() << "New Files/Dirs added: " << newFile;

foreach(QString file, newFile)

{

// 处理操作每个新文件....

}

}

// 从Dir中删除文件/目录

if (!deleteFile.isEmpty())

{

qDebug() << "Files/Dirs deleted: " << deleteFile;

foreach(QString file, deleteFile)

{

// 处理操作每个被删除的文件....

}

}

}

}

// 文件修改时调用

void XFileSystemWatcher::fileUpdated(const QString& path)

{

QFileInfo file(path);

QString strPath = file.absolutePath();

QString strName = file.fileName();

qDebug() << QString("The file %1 at path %2 is updated").arg(strName).arg(strPath);

}

Main.cpp

#include <QCoreApplication>

#include "XFileSystemWatcher.h"

int main(int argc, char* argv[])

{

QCoreApplication a(argc, argv);

XFileSystemWatcher::addWatchPath("D:/360");

return a.exec();

}

主要函数调用流程及原理

QFileSystemWatcher::addPath

使用API函数FindFirstChangeNotification、FindNextChangeNotification进行监视。

写到最后

目前先写到这,诸位无论是有什么意见或建议都可以写到评论区,下来一起探讨

猜你喜欢

转载自blog.csdn.net/sinat_36391009/article/details/130940773