1. 程式人生 > 實用技巧 >Qt實戰4.簡單封裝的檔案監控

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

完整程式碼