C++ Qt開發:QFileSystemWatcher文件監視組件

Qt 是一個跨平臺C++圖形界面開發庫,利用Qt可以快速開發跨平臺窗體應用程序,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實現圖形化開發極大的方便了開發效率,本章將重點介紹如何運用QFileSystemWatcher組件實現對文件或目錄的監視功能。

QFileSystemWatcher 是 Qt 框架中提供的一個類,用於監視文件系統中的文件和目錄的變化。它允許你在文件或目錄發生變化時接收通知,並可以用於監視文件的創建、刪除、重命名以及內容修改等操作。這對於需要實時監控文件系統變化的應用程序是非常有用的。

下面是關於 QFileSystemWatcher 類的一些常用函數的解釋:

函數 描述
QFileSystemWatcher(QObject *parent = nullptr) 構造函數,創建一個文件系統監視器對象。
void addPath(const QString &path) 添加要監視的文件或目錄路徑。
void addPaths(const QStringList &paths) 添加要監視的多個文件或目錄路徑。
bool removePath(const QString &path) 移除要監視的文件或目錄路徑。
void removePaths(const QStringList &paths) 移除要監視的多個文件或目錄路徑。
bool contains(const QString &path) const 檢查監視器是否包含指定的文件或目錄路徑。
QStringList files() const 返回當前監視的文件路徑列表。
QStringList directories() const 返回當前監視的目錄路徑列表。
void setFilter(QFileSystemWatcher::Filter filter) 設置監視器的過濾器,用於指定要監視的事件類型。
QFileSystemWatcher::Filter filter() const 返回監視器當前的過濾器設置。
void fileChanged(const QString &path) 信號,當監視的文件發生變化時發出。
void directoryChanged(const QString &path) 信號,當監視的目錄發生變化時發出。

這些函數允許你動態地添加或移除要監視的文件或目錄,設置過濾器以確定要監視的事件類型,並連接相應的信號以處理文件系統的變化事件。

首先我們需要新增一個filesystem.h頭文件,該類主要用於實現對文件訪問的封裝,其中addWatchPath用於增加一個被監控目錄,當目錄被更新世則調用directoryUpdated,文件被修改調用fileUpdated

#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#include <QObject>
#include <QMap>
#include <QString>
#include <QMap>
#include <QFileSystemWatcher>

class FileSystemWatcher : public QObject
{
    Q_OBJECT

public:
    static void addWatchPath(QString path);

public slots:

    // 目錄更新時調用
    void directoryUpdated(const QString &path);

    // 文件被修改時調用
    void fileUpdated(const QString &path);

private:
    explicit FileSystemWatcher(QObject *parent = 0);

private:
    // 單例
    static FileSystemWatcher *m_pInstance;

    // QFileSystemWatcher變量
    QFileSystemWatcher *m_pSystemWatcher;

    // 當前每個監控的內容目錄列表
    QMap<QString, QStringList> m_currentContentsMap;
};

#endif // FILESYSTEM_H

接着是filesystem.cpp主函數部分,首先FileSystemWatcher::addWatchPath用於增加一個監控目錄。這裏的重點在於創建兩個信號,當m_pSystemWatcher收到監控數據時,我們讓其分別去觸發directoryChangedfileChanged兩個信號,在信號中分別攜帶一個參數傳遞給directoryUpdatedfileUpdated槽函數上進行處理,如果是目錄則保存目錄中的內容。

void FileSystemWatcher::addWatchPath(QString path)
{
   qDebug() << QString("添加監控目錄: %1").arg(path);

    if (m_pInstance == NULL)
    {
        m_pInstance = new FileSystemWatcher();
        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);
    }
}

接着是FileSystemWatcher::directoryUpdated函數的實現部分,如下所示代碼,通過QFileSystemWatcher來監聽指定目錄下文件和子目錄的變化。當目錄發生變化時,調用directoryUpdated槽函數,比較最新的目錄內容和之前保存的內容,找出新增文件、刪除文件以及文件重命名等變化。

  • 功能概述
    1. 添加監控路徑:通過addWatchPath函數添加監控路徑,創建QFileSystemWatcher對象並連接相關信號和槽。
    2. 目錄更新處理:當監控的目錄發生變化時,調用directoryUpdated槽函數。
    3. 內容變化比較:比較最新的目錄內容和之前保存的內容,找出新增文件、刪除文件和文件重命名等變化。
    4. 文件重命名處理:如果有文件重命名,輸出文件重命名的信息。
    5. 新增文件處理:輸出新建文件的信息,並可以在相應的邏輯中處理每個新文件。
    6. 刪除文件處理:輸出刪除文件的信息,並可以在相應的邏輯中處理每個被刪除的文件。

代碼對文件系統的變化進行了細緻的監控和處理,可以用於實時監控目錄下文件的變動情況,例如新增文件、刪除文件和文件重命名等操作。當用戶需要自定義功能時可以在信息輸出前對特定目錄做進一步處理以達到監視並控制特定文件的功能。

// 任何監控的目錄更新(添加、刪除、重命名)則調用
void FileSystemWatcher::directoryUpdated(const QString &path)
{
    qDebug() << QString("目錄更新: %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("文件重命名 %1 到 %2").arg(deleteFile.first()).arg(newFile.first());
        }
    }
    else
    {
        // 添加新文件/目錄至Dir
        if (!newFile.isEmpty())
        {
           qDebug() << "新建文件或目錄: " << newFile;

            foreach (QString file, newFile)
            {
                // 處理操作每個新文件....
            }
        }

        // 從Dir中刪除文件/目錄
        if (!deleteFile.isEmpty())
        {
            qDebug() << "刪除文件或目錄: " << deleteFile;

            foreach(QString file, deleteFile)
            {
                // 處理操作每個被刪除的文件....
            }
        }
    }
}

同理,當文件被修改時則調用fileUpdated函數,只需要去除絕對路徑與文件名即可,如下代碼所示;

void FileSystemWatcher::fileUpdated(const QString &path)
{
    QFileInfo file(path);
    QString strPath = file.absolutePath();
    QString strName = file.fileName();

   qDebug() << QString("文件 %1 路徑 %2 修改").arg(strName).arg(strPath);
}

你可以自行運行課件FileSystemWatcher.zip來觀察監控效果,如下圖;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章