In this article I will show you how to use the C++17 std::filesystem library to write a simple file watcher or file monitor. The advantage of using the C++17 std::filesystem library is that your code will be portable on all operating systems for which a C++17 compiler is available.
We are going to implement a C++17 file watcher that will monitor a given folder for file changes. For our limited purposes, we’ll monitor only the creation, modification and deletion of all files from the watched directory. The base folder will be checked for changes at regular time intervals and, in case of changes, we’ll run a user defined function.
Disclaimer: The code presented in this article is not meant to be used as is in production. The code was written as an exercise or demo to show what you can do with the C++17 std::filesystem library. If you want the ultimate performance, you should try to use the operating system functions like inotify on Linux or kqueue on macOS and FreeBSD.
At the time of this writing, you can use the C++17 std::filesystem library with GCC 9, Clang 7 and MSVC 2017. Here is an example of compiling a C++ program that uses std::filesystem with GCC:
Clang 8:
Clang 9 and up:
Please note that, at the time this writing, Apple’s Clang from Xcode 10 or the Command Line Tools doesn’t support the std::filesystem library. If you want to install GCC 9 on your macOS check this article.
We’ll start by writing a FileWatcher class that will check a given folder for changes at regular intervals. Here is an example of how I want to be able to use our FileWatcher class:
Let’s start by defining the list of possible file changes (creation, modification, deletion) in FileWatcher.h:
Next, we can start writing the FileWatcher class. If we want to be able to monitor what file was changed, we’ll need a way to keep a record of the existing files in the watched folder. A simple approach is to use a hash table that will have as keys the file path and as values the time of the last modification of the file. We can use a std::unordered_map to store the above:
Now, we can implement the function that will start monitoring the base folder path_to_watch for changes:
The start function will start an infinite loop in which we wait delay milliseconds and than we check for file changes. If a change is detected, we call the user defined action function that receives as parameters the file path, as a string, and the type of change detected.
Please note the contains function that checks if a given key is present in the paths_. The C++20 standard will add a contains member function to std::unordered_map, at which time you can replace line 28 from the above code with something like:
and remove our contains function.
At this point, FileWatcher.h is complete. Here is an example of using it to monitor the current folder for changes every five seconds:
In the above code, the user has supplied a lambda function that will be called when a file change is detected.
You can find the complete source code on the GitHub repository for this article.
Next, I will show you an example of building, running and testing the above code on my machine. I’ve used two Terminal windows, one for interacting with the program and one for file operations. Here is the first window output:
Second window output:
If you are interested to learn more about modern C++ I would recommend reading A tour of C++ by Bjarne Stroustrup.