Qt实战4.简单封装的文件监控

1 需求描述

  1. 实现一个类能够监控单个目录内文件的变化;
  2. 能够识别文件的创建、改变、删除三种变化。

2 设计思路

Qt自带的QFileSystemWatcher提供了一些接口,通过addPath添加一个路径即可对该目录进行监视,当目录发生改变时(比如添加和删除文件)会发出directoryChanged信号,还有个fileChanged信号主要针对单个文件,这里不涉及。
对于创建了什么文件,删除了什么文件,以及文件名从什么改变成了什么,这些都是无法直接获取到的,如果监视目录后有以下三个信号岂不美哉。

//文件创建信号
void fileCreated(const QString &fileName);
//文件名改变信号
void fileNameChanged(const QString &previousFileName, const QString &currentFileName);
//文件删除信号
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 下载

完整代码

原文地址:https://www.cnblogs.com/luoxiang/p/13474185.html