QFileSystemWatcher技术

QFileSystemWatcher 类概述

在 Qt 中,QFileSystemWatcher 类提供了一种方便的方式来监视文件和目录的变化。当被监视的文件或目录发生修改、重命名或删除时,该类会发出相应的信号,使应用程序能够及时响应这些变化。

核心功能与方法

1. 添加监视路径

· addPath(const QString &path):添加单个文件或目录到监视列表

· addPaths(const QStringList &paths):添加多个文件或目录到监视列表

2. 移除监视路径

· removePath(const QString &path):从监视列表中移除单个文件或目录

· removePaths(const QStringList &paths):从监视列表中移除多个文件或目录

3. 获取当前监视的路径

· files():返回正在监视的文件列表

· directories():返回正在监视的目录列表

4. 信号

· fileChanged(const QString &path):当监视的文件发生变化时发出

· directoryChanged(const QString &path):当监视的目录发生变化时发出

代码示例:文件系统监视器

下面是一个完整的示例,展示如何使用 QFileSystemWatcher 来监视文件和目录的变化:

#include <QApplication>
#include <QMainWindow>
#include <QFileSystemWatcher>
#include <QTextEdit>
#include <QListWidget>
#include <QPushButton>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSplitter>
#include <QLabel>
#include <QDateTime>
#include <QMessageBox>
class FileSystemWatcherDemo : public QMainWindow {
Q_OBJECT
public:
FileSystemWatcherDemo(QWidget *parent = nullptr) : QMainWindow(parent) {
setupUI();
setupConnections();

// 初始化文件系统监视器
watcher = new QFileSystemWatcher(this);
connect(watcher, &QFileSystemWatcher::fileChanged, this, &FileSystemWatcherDemo::onFileChanged);
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &FileSystemWatcherDemo::onDirectoryChanged);

setWindowTitle(“Qt文件系统监视器示例”);
resize(800, 600);
}
private slots:
void onAddFile() {
QString filePath = QFileDialog::getOpenFileName(this, “选择要监视的文件”);
if (!filePath.isEmpty()) {
if (watcher->addPath(filePath)) {
addToWatchList(filePath, true);
logMessage(“已添加文件监视: ” + filePath);
} else {
logMessage(“无法监视文件: ” + filePath);
}
}
}

void onAddDirectory() {
QString dirPath = QFileDialog::getExistingDirectory(this, “选择要监视的目录”);
if (!dirPath.isEmpty()) {
if (watcher->addPath(dirPath)) {
addToWatchList(dirPath, false);
logMessage(“已添加目录监视: ” + dirPath);
} else {
logMessage(“无法监视目录: ” + dirPath);
}
}
}

void onRemoveSelected() {
QList<QListWidgetItem*> selectedItems = watchList->selectedItems();
for (QListWidgetItem *item : selectedItems) {
QString path = item->text();
bool isFile = item->data(Qt::UserRole).toBool();

if (isFile ? watcher->removePath(path) : watcher->removePath(path)) {
logMessage(“已移除监视: ” + path);
delete item;
} else {
logMessage(“无法移除监视: ” + path);
}
}
}

void onClearAll() {
QStringList files = watcher->files();
QStringList directories = watcher->directories();

if (!files.isEmpty()) watcher->removePaths(files);
if (!directories.isEmpty()) watcher->removePaths(directories);

watchList->clear();
logMessage(“已清除所有监视路径”);
}

void onFileChanged(const QString &path) {
logMessage(“文件发生变化: ” + path + ” – ” + QDateTime::currentDateTime().toString());

// 如果文件被删除,自动从监视列表中移除
if (!QFile::exists(path)) {
watcher->removePath(path);
removeFromWatchList(path);
logMessage(“文件已被删除,自动移除监视: ” + path);
}
}

void onDirectoryChanged(const QString &path) {
logMessage(“目录发生变化: ” + path + ” – ” + QDateTime::currentDateTime().toString());

// 如果目录被删除,自动从监视列表中移除
if (!QDir(path).exists()) {
watcher->removePath(path);
removeFromWatchList(path);
logMessage(“目录已被删除,自动移除监视: ” + path);
}
}
private:
void setupUI() {
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);

QSplitter *splitter = new QSplitter(Qt::Vertical, centralWidget);

// 上部区域:监视列表和控制按钮
QWidget *topWidget = new QWidget;
QVBoxLayout *topLayout = new QVBoxLayout(topWidget);

QLabel *listLabel = new QLabel(“监视列表:”);
watchList = new QListWidget;

QHBoxLayout *buttonLayout = new QHBoxLayout;
QPushButton *addFileBtn = new QPushButton(“添加文件”);
QPushButton *addDirBtn = new QPushButton(“添加目录”);
QPushButton *removeBtn = new QPushButton(“移除选中”);
QPushButton *clearBtn = new QPushButton(“清除所有”);

buttonLayout->addWidget(addFileBtn);
buttonLayout->addWidget(addDirBtn);
buttonLayout->addWidget(removeBtn);
buttonLayout->addWidget(clearBtn);
buttonLayout->addStretch();

topLayout->addWidget(listLabel);
topLayout->addWidget(watchList);
topLayout->addLayout(buttonLayout);

// 下部区域:日志显示
QWidget *bottomWidget = new QWidget;
QVBoxLayout *bottomLayout = new QVBoxLayout(bottomWidget);

QLabel *logLabel = new QLabel(“监视日志:”);
logEdit = new QTextEdit;
logEdit->setReadOnly(true);

bottomLayout->addWidget(logLabel);
bottomLayout->addWidget(logEdit);

splitter->addWidget(topWidget);
splitter->addWidget(bottomWidget);
splitter->setSizes(QList<int>() << 200 << 400);

QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
mainLayout->addWidget(splitter);

// 连接按钮信号
connect(addFileBtn, &QPushButton::clicked, this, &FileSystemWatcherDemo::onAddFile);
connect(addDirBtn, &QPushButton::clicked, this, &FileSystemWatcherDemo::onAddDirectory);
connect(removeBtn, &QPushButton::clicked, this, &FileSystemWatcherDemo::onRemoveSelected);
connect(clearBtn, &QPushButton::clicked, this, &FileSystemWatcherDemo::onClearAll);
}

void setupConnections() {
// 连接列表项双击事件
connect(watchList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem *item) {
QString path = item->text();
if (item->data(Qt::UserRole).toBool()) {
// 是文件
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
} else {
// 是目录
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(path).path()));
}
});
}

void addToWatchList(const QString &path, bool isFile) {
QListWidgetItem *item = new QListWidgetItem(path);
item->setData(Qt::UserRole, isFile);
item->setIcon(isFile ? QIcon(“:/icons/file.png”) : QIcon(“:/icons/folder.png”));
watchList->addItem(item);
}

void removeFromWatchList(const QString &path) {
for (int i = 0; i < watchList->count(); ++i) {
QListWidgetItem *item = watchList->item(i);
if (item->text() == path) {
delete watchList->takeItem(i);
break;
}
}
}

void logMessage(const QString &message) {
logEdit->append(“[” + QDateTime::currentDateTime().toString(“hh:mm:ss”) + “] ” + message);
}
private:
QFileSystemWatcher *watcher;
QListWidget *watchList;
QTextEdit *logEdit;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);

FileSystemWatcherDemo demo;
demo.show();

return app.exec();
}
#include “main.moc”

关键技术点详解

1. 初始化文件系统监视器

watcher = new QFileSystemWatcher(this);
connect(watcher, &QFileSystemWatcher::fileChanged, this, &FileSystemWatcherDemo::onFileChanged);
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &FileSystemWatcherDemo::onDirectoryChanged);

创建 QFileSystemWatcher 实例并连接其信号到相应的槽函数。

2. 添加监视路径

if (watcher->addPath(filePath)) {
addToWatchList(filePath, true);
logMessage(“已添加文件监视: ” + filePath);
} else {
logMessage(“无法监视文件: ” + filePath);
}

使用 addPath() 方法添加单个监视路径,并根据返回值判断是否成功。

3. 处理文件变化事件

void onFileChanged(const QString &path) {
logMessage(“文件发生变化: ” + path + ” – ” + QDateTime::currentDateTime().toString());

// 如果文件被删除,自动从监视列表中移除
if (!QFile::exists(path)) {
watcher->removePath(path);
removeFromWatchList(path);
logMessage(“文件已被删除,自动移除监视: ” + path);
}
}

当文件发生变化时,记录日志并检查文件是否依旧存在。如果文件被删除,自动从监视列表中移除。

4. 处理目录变化事件

void onDirectoryChanged(const QString &path) {
logMessage(“目录发生变化: ” + path + ” – ” + QDateTime::currentDateTime().toString());

// 如果目录被删除,自动从监视列表中移除
if (!QDir(path).exists()) {
watcher->removePath(path);
removeFromWatchList(path);
logMessage(“目录已被删除,自动移除监视: ” + path);
}
}

当目录发生变化时,记录日志并检查目录是否依旧存在。如果目录被删除,自动从监视列表中移除。

5. 移除监视路径

if (isFile ? watcher->removePath(path) : watcher->removePath(path)) {
logMessage(“已移除监视: ” + path);
delete item;
} else {
logMessage(“无法移除监视: ” + path);
}

使用 removePath() 方法移除单个监视路径,并根据返回值判断是否成功。

实际应用场景

1. 配置文件监视:当应用程序的配置文件被修改时,自动重新加载配置

2. 自动构建系统:当源代码文件发生变化时,自动触发构建过程

3. 文件同步工具:当源目录中的文件发生变化时,自动同步到目标目录

4. 日志文件监视:当日志文件被更新时,实时显示最新内容

5. 资源文件热重载:在开发过程中,当资源文件发生变化时,自动更新应用程序界面

注意事项

1. 性能思考:监视大量文件或目录可能会影响系统性能

2. 文件系统限制:某些文件系统可能不支持文件监视功能

3. 路径有效性:当监视的路径被删除时,需要及时从监视列表中移除

4. 符号链接:符号链接的行为可能因操作系统而异

5. 网络文件系统:网络文件系统的监视可能不可靠或有限制

总结

QFileSystemWatcher 是 Qt 提供的一个强劲工具,用于监视文件和目录的变化。通过简单的 API,开发者可以轻松实现文件系统变化的实时监控和响应。在实际应用中,合理使用 QFileSystemWatcher 可以大大增强应用程序的交互性和自动化能力。

© 版权声明

相关文章

暂无评论

none
暂无评论...