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 下載

完整代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM