Qt/C++ cross-platform file system watcher library using JetBrains fsnotifier.
If you're using Qt and QFileSystemWatcher can't meet your demands, try this one.
IntelliJ IDEA uses a child process to notify the host of file system changes safely and efficiently.
The source code of IntelliJ IDEA community edition has been published on JetBrains GitHub homepage, and the source code of fsnotifier is in directory named "native".
Since fsnotifier is coded in C, there are three different pieces of codes for Windows, Mac, and Linux. You need to use CMake to compile different codes on different OS to build the platform dependent executable, on Windows, it's usually called fsnotifier.exe.
https://github.com/JetBrains/intellij-community
https://github.com/JetBrains/intellij-community/tree/master/native/WinFsNotifier
https://github.com/JetBrains/intellij-community/tree/master/native/fsNotifier
This is the Qt library that can manage JetBrains Filesystem events processor.
Most codes are C++ implementations of related Java code in IDEA.
The main task of the library is to manage the fsnotifier sub-process, send optimized directory information provided by the frontend to fsnotifier through IPC and receive output, and encapsulate the received path and return it to the frontend.
Qt 5.14 or later is required.
#include <QCoreApplication>
#include <QDebug>
#include "FileSystemNotifier.h"
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// Make sure to place the fsnotifier executable in the working directory
FileSystemNotifier fs;
fs.startWatch();
// Print dirty paths
QObject::connect(&fs, &FileSystemNotifier::changed, [](const QStringList &paths) {
qDebug() << "[Paths changed]";
std::for_each(paths.begin(), paths.end(), [](const QString &path) {
qDebug().noquote() << path;
});
});
QObject::connect(&fs, &FileSystemNotifier::renamed, [](const QStringList &paths) {
qDebug() << "[Paths renamed]";
std::for_each(paths.begin(), paths.end(),[](const QString &path) {
qDebug().noquote() << path;
});
});
// Watch "C:/foo" recursively and "D:/bar" non-recursively
fs.addRecursivePaths({"C:/foo"});
fs.addFlatPaths({"D:/bar"});
return a.exec();
}
If a file or directroy is renamed(created or removed), signal "renamed" will be emitted.
If a file or directory is changed, signal "changed" will be emitted.
And for its parent directroy, signal "changed" will be emitted.
#include <QCoreApplication>
#include "JBFileWatchNamespace.h"
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// Make sure to place the fsnotifier executable in the working directory
JB::LocalFileSystem fs;
fs.start();
// Print dirty paths
QObject::connect(&fs, &JB::LocalFileSystem::pathsDirty, [](const QStringList &dirtyPaths) {
qDebug() << "[Paths dirty]";
std::for_each(dirtyPaths.begin(), dirtyPaths.end(), [](const QString &path) {
qDebug() << path;
});
});
QObject::connect(&fs, &JB::LocalFileSystem::flatDirsDirty, [](const QStringList &dirtyPaths) {
qDebug() << "[Non-recursive dirs dirty]";
std::for_each(dirtyPaths.begin(), dirtyPaths.end(), [](const QString &path) {
qDebug() << path;
});
});
QObject::connect(&fs, &JB::LocalFileSystem::recursivePathsDirty, [](const QStringList &dirtyPaths) {
qDebug() << "[Recursive paths dirty]";
std::for_each(dirtyPaths.begin(), dirtyPaths.end(), [](const QString &path) {
qDebug() << path;
});
});
QList<JB::WatchRequest> requests;
// Watch "C:/foo" recursively and "D:/bar" non-recursively
requests = fs.replaceWatchedRoots({}, {"C:/foo"}, {"D:/bar"});
return a.exec();
}
If a file or directroy is renamed(created or removed), signal "recursivePathsDirty" will be emitted.
If a file or directory is changed, signal "pathsDirty" or "flatDirsDirty" will be emitted.
And for its parent directroy, signal "pathsDirty" will be emitted.
// #define JB_NO_DEBUG_OUTPUT
// #define JB_NO_WARNING_OUTPUT
Uncomment the lines in JBFileWatcherUtils.h to disable debug output and warning output.
As long as JB::LocalFileSystem::start() is called, then JB::LocalFileSystem::dispose() is recommended to be called before QCoreApplication quits although it will call automatically after signal QCoreApplication::aboutToQuit emitted.