Qt源码那些事儿-QFileSystemWatcher-Qt的一个未放开的类

发布于 2020-02-26  354 次阅读


前言

上一篇讲了QFileSystemWatcher来检测文件夹的变化,里边的实现有两个


// 这个用于检测文件类型的变化 class QInotifyFileSystemWatcherEngine : public QFileSystemWatcherEngine // 这个用于监控Dir的变化 class QDnotifyFileSystemWatcherEngine : public QFileSystemWatcherEngine

QFileSystemWatcher中这两个类监视文件夹的变化还有一个小小的缺点,就是无法监视连接到服务器的位置,一般挂载到服务器到Linux本地的路径是这里


/run/user/1000/gvfs

这个目录下的。没有办法只能自己暂时实现了。

多线程 + 定时器

实际上一开始准备自己实现的,但是发现QFileSystemWatcher里边已经有一个类是对应的实现了。


enum { PollingInterval = 1000 }; class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine { Q_OBJECT class FileInfo { uint ownerId; uint groupId; QFile::Permissions permissions; QDateTime lastModified; QStringList entries; public: FileInfo(const QFileInfo &fileInfo) : ownerId(fileInfo.ownerId()), groupId(fileInfo.groupId()), permissions(fileInfo.permissions()), lastModified(fileInfo.lastModified()) { if (fileInfo.isDir()) { entries = fileInfo.absoluteDir().entryList(QDir::AllEntries); } } FileInfo &operator=(const QFileInfo &fileInfo) { *this = FileInfo(fileInfo); return *this; } bool operator!=(const QFileInfo &fileInfo) const { if (fileInfo.isDir() && entries != fileInfo.absoluteDir().entryList(QDir::AllEntries)) return true; return (ownerId != fileInfo.ownerId() || groupId != fileInfo.groupId() || permissions != fileInfo.permissions() || lastModified != fileInfo.lastModified()); } }; mutable QMutex mutex; QHash<QString, FileInfo> files, directories; public: QPollingFileSystemWatcherEngine(); void run(); QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); void stop(); private Q_SLOTS: void timeout(); }; //--cpp #include "filewatcher.h" QPollingFileSystemWatcherEngine::QPollingFileSystemWatcherEngine() { #ifndef QT_NO_THREAD moveToThread(this); #endif } void QPollingFileSystemWatcherEngine::run() { QTimer timer; connect(&timer, SIGNAL(timeout()), SLOT(timeout())); timer.start(PollingInterval); (void) exec(); } QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files, QStringList *directories) { QMutexLocker locker(&mutex); QStringList p = paths; QMutableListIterator<QString> it(p); while (it.hasNext()) { QString path = it.next(); QFileInfo fi(path); if (!fi.exists()) continue; if (fi.isDir()) { if (!directories->contains(path)) directories->append(path); if (!path.endsWith(QLatin1Char('/'))) fi = QFileInfo(path + QLatin1Char('/')); this->directories.insert(path, fi); } else { if (!files->contains(path)) files->append(path); this->files.insert(path, fi); } it.remove(); } start(); return p; } QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &paths, QStringList *files, QStringList *directories) { QMutexLocker locker(&mutex); QStringList p = paths; QMutableListIterator<QString> it(p); while (it.hasNext()) { QString path = it.next(); if (this->directories.remove(path)) { directories->removeAll(path); it.remove(); } else if (this->files.remove(path)) { files->removeAll(path); it.remove(); } } if (this->files.isEmpty() && this->directories.isEmpty()) { locker.unlock(); stop(); wait(); } return p; } void QPollingFileSystemWatcherEngine::stop() { QMetaObject::invokeMethod(this, "quit"); } void QPollingFileSystemWatcherEngine::timeout() { QMutexLocker locker(&mutex); QMutableHashIterator<QString, FileInfo> fit(files); while (fit.hasNext()) { QHash<QString, FileInfo>::iterator x = fit.next(); QString path = x.key(); QFileInfo fi(path); if (!fi.exists()) { fit.remove(); emit fileChanged(path, true); } else if (x.value() != fi) { x.value() = fi; emit fileChanged(path, false); } } QMutableHashIterator<QString, FileInfo> dit(directories); while (dit.hasNext()) { QHash<QString, FileInfo>::iterator x = dit.next(); QString path = x.key(); QFileInfo fi(path); if (!path.endsWith(QLatin1Char('/'))) fi = QFileInfo(path + QLatin1Char('/')); if (!fi.exists()) { dit.remove(); emit directoryChanged(path, true); } else if (x.value() != fi) { fi.refresh(); if (!fi.exists()) { dit.remove(); emit directoryChanged(path, true); } else { x.value() = fi; emit directoryChanged(path, false); } } } }
// 这个外部没有暴露对应的变化接口,但是检测其它类型的目录变化时我们会用到
class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine

这个类Qt没有对外接口暴露,实际上看QFileSystemWatcher的实现

//poller在这里初始化
void QFileSystemWatcherPrivate::initPollerEngine()
{
    if(poller)
        return;
    Q_Q(QFileSystemWatcher);
    poller = new QPollingFileSystemWatcherEngine; // that was a mouthful
    QObject::connect(poller,
                     SIGNAL(fileChanged(QString,bool)),
                     q,
                     SLOT(_q_fileChanged(QString,bool)));
    QObject::connect(poller,
                     SIGNAL(directoryChanged(QString,bool)),
                     q,
                     SLOT(_q_directoryChanged(QString,bool)));
}

//在这里调用
    if(!objectName().startsWith(QLatin1String("_qt_autotest_force_engine_"))) {   //这里也就是
        // Normal runtime case - search intelligently for best engine
        if(d->native) {
            engine = d->native;
        } else {
            d_func()->initPollerEngine();       //这里初始化,否则就走上边两个无法监视服务器的实现
            engine = d->poller;
        }

发现QFileSystemWatcher设置objectName为qt_autotest_force_engine 就可以使用了。
然后接着

    QFileSystemWatcher* fileSystemWatcher = new QFileSystemWatcher(this);
    fileSystemWatcher->setObjectName(QLatin1String("_qt_autotest_force_engine_"));

这样就可以监视

/run/user/1000/gvfs

目录下的文件,也就是服务器挂载到Linux本地下的文件变化了。

欢迎关注我的小程序,小程序内容与网站自动保持同步

欢迎关注我的微信公众号,本网站所有的文章以及更新以后都会手动同步到微信公众号上。


公交车司机终于在众人的指责中将座位让给了老太太