Qt实战4.简单封装的文件监控
1 需求描述
- 实现一个类能够监控单个目录内文件的变化;
- 能够识别文件的创建、改变、删除三种变化。
2 设计思路
Qt自带的QFileSystemWatcher提供了一些接口,通过addPath添加一个路径即可对该目录进行监视,当目录发生改变时(比如添加和删除文件)会发出directoryChanged信号,还有个fileChanged信号主要针对单个文件,这里不涉及。
对于创建了什么文件,删除了什么文件,以及文件名从什么改变成了什么,这些都是无法直接获取到的,如果监视目录后有以下三个信号岂不美哉。
//文件创建信号
void fileCreated(const QString &fileName);
//文件名改变信号
void fileNameChanged(const QString &previousFileName, const QString ¤tFileName);
//文件删除信号
void fileRemoved(const QString &fileName);
下面开始造,实现很简单,维护一个文件列表(目录改变前),被监视目录改变后在槽函数中和当前文件列表(目录改变后)进行比对,从而判断文件的变化状态,然后发射对应的信号。
3 代码实现
3.1 添加监视目录
继承QFileSystemWatcher,然后添加一个监视目录,相关代码如下:
CustomFileWatcher::CustomFileWatcher(QObject *parent) :
QFileSystemWatcher(parent)
{
connect(this, &CustomFileWatcher::directoryChanged, this, &CustomFileWatcher::onDirectoryChanged);
}
CustomFileWatcher::CustomFileWatcher(const QString &path, QObject *parent) :
QFileSystemWatcher(QStringList(path), parent)
{
QFileSystemWatcher::addPath(path);
QDir dir(path);
dir.setFilter(QDir::NoDotAndDotDot | QDir::AllEntries);
m_fileEntryList = dir.entryList();
connect(this, &CustomFileWatcher::directoryChanged, this, &CustomFileWatcher::onDirectoryChanged);
}
void CustomFileWatcher::addPath(const QString &path)
{
if (!directories().isEmpty()) {
removePath(directories().first());
}
QFileSystemWatcher::addPath(path);
QDir dir(path);
dir.setFilter(QDir::NoDotAndDotDot | QDir::AllEntries);
m_fileEntryList = dir.entryList();
}
3.2 判断文件状态
进入目录改变槽函数,内部通过文件列表(变化前和变化后)的比对,从而判断目录内文件的变化状态,发射对应信号,代码如下:
void CustomFileWatcher::onDirectoryChanged(const QString &path)
{
QDir dir(path);
dir.setFilter(QDir::NoDotAndDotDot | QDir::AllEntries);
QStringList fileEntryList = dir.entryList();
int previousFileCount = m_fileEntryList.count();
int currentFileCount = fileEntryList.count();
if (previousFileCount == currentFileCount) {
for (int i = 0; i < previousFileCount; i++) {
QString previousFileName = m_fileEntryList.at(i);
if (!fileEntryList.contains(previousFileName)) {
for (int j = 0; j < currentFileCount; j++) {
QString currentFileName = fileEntryList.at(j);
if (!m_fileEntryList.contains(currentFileName)) {
emit fileNameChanged(previousFileName, currentFileName);
m_fileEntryList = fileEntryList;
return;
}
}
}
}
} else if (previousFileCount > currentFileCount) {
for (int i = 0; i < currentFileCount; i++) {
m_fileEntryList.removeOne(fileEntryList.at(i));
}
emit fileRemoved(m_fileEntryList.first());
m_fileEntryList = fileEntryList;
} else {
QStringList tempList = fileEntryList;
for (int i = 0; i < previousFileCount; i++) {
tempList.removeOne(m_fileEntryList.at(i));
}
emit fileCreated(tempList.first());
m_fileEntryList = fileEntryList;
}
}
到此,单目录内文件监控功能就算完成了。
使用的时候只需要添加监视目录再连接相关信号槽即可,目录内文件的变化状态就能获取到了,是不是很简单呢?
connect(&m_fileWatcher, &CustomFileWatcher::fileNameChanged, this, &MainWindow::onFileNameChanged);
connect(&m_fileWatcher, &CustomFileWatcher::fileCreated, this, &MainWindow::onFileCreated);
connect(&m_fileWatcher, &CustomFileWatcher::fileRemoved, this, &MainWindow::onFileRemoved);
4 总结
根据需求,通过对QFileSystemWatcher简单的封装实现对单个目录内文件变化的监视,外部通过信号槽方式进行后续处理(比如文件的上传、同步等)。其实本例子程序还可以做不少拓展,比如多目录同时监控、目录递归监控等,实现可能会稍稍复杂一点,但是再复杂的功能也是从简单的开始,有个好的开端总是很重要的。
本例子程序如果对多文件同时删除,可能获取不准确,尽量进行单文件操作。
5 下载
作者QQ:115124903,欢迎交流。
每一步踏出,都是一次探索,一次成长。
每一步踏出,都是一次探索,一次成长。