Qt實戰4.簡單封裝的檔案監控
阿新 • • 發佈:2020-08-11
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簡單的封裝實現對單個目錄內檔案變化的監視,外部通過訊號槽方式進行後續處理(比如檔案的上傳、同步等)。其實本例子程式還可以做不少拓展,比如多目錄同時監控、目錄遞迴監控等,這些拓展可能會稍稍複雜一點,但是再複雜的功能也是從簡單的開始,有個好開頭總是很重要的。
本例子程式如果對多檔案同時刪除,可能獲取不準確,儘量進行單檔案操作。