深度
本文主要分析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进行监视。
写到最后
目前先写到这,诸位无论是有什么意见或建议都可以写到评论区,下来一起探讨