Watching for Directory Changes using std::filesystem
Can I watch a directory for changes using std::filesystem
?
std::filesystem
does not provide built-in support for watching a directory for changes. To achieve this, you need to use platform-specific APIs or third-party libraries.
On Windows, you can use the ReadDirectoryChangesW()
function to watch for directory changes. Here's a basic example using Windows API:
#include <windows.h>
#include <iostream>
void watch_directory(
const std::wstring &directory) {
HANDLE dir_handle = CreateFileW(
directory.c_str(),
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE
| FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
nullptr)
;
if (dir_handle == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open directory\n";
return;
}
char buffer[1024];
DWORD bytes_returned;
while (true) {
if (ReadDirectoryChangesW(
dir_handle, buffer, sizeof(buffer), TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME
| FILE_NOTIFY_CHANGE_DIR_NAME
| FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_SECURITY,
&bytes_returned,
nullptr,
nullptr
)) {
FILE_NOTIFY_INFORMATION *info =
reinterpret_cast<
FILE_NOTIFY_INFORMATION *>(buffer);
std::wcout << "Change detected in: "
<< info->FileName << '\n';
} else {
std::cerr
<< "Failed to read directory changes\n";
}
}
CloseHandle(dir_handle);
}
int main() {
watch_directory(L"c:\\test");
}
Change detected in: newfile.txt
In this example:
CreateFile
opens the directory for monitoring.ReadDirectoryChangesW
watches for changes in the directory and reports them.- We print the name of the file that changed whenever a change is detected.
On Linux, you can use the inotify
API to watch for directory changes. Here's a basic example using inotify
:
#include <limits.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <iostream>
void watch_directory(const std::string &directory) {
int inotify_fd = inotify_init();
if (inotify_fd < 0) {
std::cerr << "Failed to initialize inotify\n";
return;
}
int watch_fd = inotify_add_watch(
inotify_fd, directory.c_str(),
IN_MODIFY | IN_CREATE | IN_DELETE
);
if (watch_fd < 0) {
std::cerr << "Failed to add watch\n";
close(inotify_fd);
return;
}
char buffer[
sizeof(struct inotify_event) + NAME_MAX + 1];
while (true) {
int length = read(
inotify_fd, buffer, sizeof(buffer));
if (length < 0) {
std::cerr << "Failed to read inotify events\n";
break;
}
struct inotify_event *event = reinterpret_cast<
struct inotify_event *>(buffer);
if (event->len) {
std::cout << "Change detected in: "
<< event->name << '\n';
}
}
inotify_rm_watch(inotify_fd, watch_fd);
close(inotify_fd);
}
int main() {
watch_directory("/tmp/test");
}
Change detected in: newfile.txt
In this example:
inotify_init
initializes the inotify instance.inotify_add_watch
adds a watch on the specified directory.read
retrieves events, and we print the name of the file that changed.
These examples show how to watch directories on different platforms. Using a cross-platform library like boost::asio
or libuv
can simplify this process by providing a consistent API across multiple operating systems.
Working with the File System
Create, delete, move, and navigate through directories and files using the std::filesystem
library.