Sane C++ Libraries
C++ Platform Abstraction Libraries
File System Watcher

🟩 Notifications {add, remove, rename, modified} for files and directories

SC::FileSystemWatcher allows watching directories for changes that happen to them.

Features

  • Get notified about modified files or directories
  • Get notified about added / removed / renamed files or directories

Status

🟩 Usable
Library does have basic capabilities and it can be used just fine.

Description

Caller can specify a callback for receiving notifications the SC::FileSystemWatcher::watch method.

Changes are grouped in two categories:

  • Added, removed and renamed files and directories
  • Modified files

There are two modes in which FileSystemWatcher can be initialized, defining how notifications are delivered:

Mode Description
SC::FileSystemWatcher::ThreadRunner Delivers notifications on a background thread.
SC::FileSystemWatcher::EventLoopRunner Delivers notifications using Async (SC::AsyncEventLoop).

Example using SC::FileSystemWatcher::EventLoopRunner:

// Initialize the FileSystemWatcher
FileSystemWatcher fileSystemWatcher;
FileSystemWatcher::EventLoopRunner eventLoopRunner(eventLoop);
SC_TRY(fileSystemWatcher.init(eventLoopRunner));
// Setup notification callback
auto onFileModified = [&](const FileSystemWatcher::Notification& notification)
{
// This callback will be called from the thread calling AsyncEventLoop::run
SmallString<1024> buffer;
StringView fullPath;
if (notification.getFullPath(buffer, fullPath))
{
switch (notification.operation)
{
case FileSystemWatcher::Operation::Modified: // File has been modified
console.print("Modified {} {}\n", notification.relativePath, fullPath);
break;
case FileSystemWatcher::Operation::AddRemoveRename: // File was added / removed
console.print("AddRemoveRename {} {}\n", notification.relativePath, fullPath);
break;
}
}
};
// Start watching a specific folder
FileSystemWatcher::FolderWatcher folderWatcher;
SC_TRY(fileSystemWatcher.watch(folderWatcher, "/path/to/dir", onFileModified));
// ...
// At a later point when there is no more need of watching the folder
SC_TRY(folderWatcher.stopWatching());
// ...
// When all watchers have been unwatched and to dispose all system resources
SC_TRY(fileSystemWatcher.close());
#define SC_TRY(expression)
Checks the value of the given expression and if failed, returns this value to caller.
Definition: Result.h:47

Example using SC::FileSystemWatcher::ThreadRunner:

// Initialize the FileSystemWatcher
FileSystemWatcher::ThreadRunner threadRunner; // <--- The thread runner
FileSystemWatcher fileSystemWatcher;
SC_TRY(fileSystemWatcher.init(threadRunner));
// Setup notification callback
auto onFileModified = [&](const FileSystemWatcher::Notification& notification)
{
// Warning! This callback is called from a background thread!
// Make sure to do proper synchronization!
SmallString<1024> buffer;
StringView fullPath;
if (notification.getFullPath(buffer, fullPath))
{
switch (notification.operation)
{
case FileSystemWatcher::Operation::Modified: // File has been modified
console.print("Modified {} {}\n", notification.relativePath, fullPath);
break;
case FileSystemWatcher::Operation::AddRemoveRename: // File was added / removed
console.print("AddRemoveRename {} {}\n", notification.relativePath, fullPath);
break;
}
}
};
// Start watching a specific folder
FileSystemWatcher::FolderWatcher folderWatcher;
SC_TRY(fileSystemWatcher.watch(folderWatcher, "/path/to/dir", onFileModified));
// ...
// At a later point when there is no more need of watching the folder
SC_TRY(folderWatcher.stopWatching());
// ...
// When all watchers have been unwatched and to dispose all system resources
SC_TRY(fileSystemWatcher.close());

Details

The class tries to unify differences between OS specific API to deliver folder change notifications

  • On Apple FSEvents by CoreServices is used.
  • On Windows ReadDirectoryChangesW is used.

The behavior between these different system also depends on the file system where the watched directory resides.

Roadmap

🟦 Complete Features:

  • Not sure what else could be useful here

💡 Unplanned Features:

  • Having a thread based polling stat watcher that checks file modifications on intervals as fallback
  • Allow users to provide their own thread instead of creating it behind the scenes