I think it's always important to get to grips with the basics and not just apply libraries.
How to monitor file changes?
What do you do, when you want to familiarize yourself with an area as a software developer? That's right, you look for the corresponding specification.
Each operating system has its own mechanism to react to file changes. Since I work on Unix, I only looked at how Unix works today. Other operating systems like Windows, BSD or macOS have their own mechanism.
Inotify - Monitoring filesystem events
There was dnotify in the beginning, but that's history!
Quoted from Wikipedia:
inotify (inode notify) is a Linux kernel subsystem created by John McCutchan, which monitors changes to the filesystem, and reports those changes to applications. It can be used to automatically update directory views, reload configuration files, log changes, backup, synchronize, and upload.
From the Linux API documentation, we can already learn quite a lot about the mechanism.
Here is just a short quote:
The inotify API provides a mechanism for monitoring filesystem events. Inotify can be used to monitor individual files, or to monitor directories. When a directory is monitored, inotify will return events for the directory itself, and for files inside the directory.
You can also take a closer look at the Linux source code.
Here is the structure of the event:
/*
* struct inotify_event - structure read from the inotify device for each event
*
* When you are watching a directory, you will receive the filename for events
* such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
*/
struct inotify_event {
__s32 wd; /* watch descriptor */
__u32 mask; /* watch mask */
__u32 cookie; /* cookie to synchronize two events */
__u32 len; /* length (including nulls) of name */
char name[]; /* stub for possible name */
};
If we take a closer look at the mode of action and data structures, we get a feeling for how the whole thing works.
Implementation in Go
Let's get back to Go. Of course, Go has good coverage of the Linux API, and we also find functions for Inotify here.
For Windows, of course, there is something comparable.
Under Go, as you would expect, there is an excellent library covering Linux, BSD and Windows.
Thus, one does not have to worry about the individual implementations.
So we put it all together.
First, we need to initialize a new watcher.
As usual in go, we have to take care of possible mistakes. Here, we react to errors with a panic.
w, err := fsnotify.NewWatcher()
if err != nil {
panic(err)
}
defer w.Close()
Now we add a directory that we want to monitor to the watcher.
err = w.Add("/tmp")
if err != nil {
panic(err)
}
The real magic then happens in its own go routine.
go func() {
for {
select {
case event, ok := <-w.Events:
if !ok {
return
}
if event.Has(fsnotify.Write) {
fmt.Println("modified file:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
fmt.Println("error:", err)
}
}
}()
With go func() {}()
we start our own go routine that runs "parallel" to the main thread.
Go routines are great, I totally love them.
Since we don't have a default statement, the select blocks the execution until an event happens.
If the operating system now reports a change to the /tmp
directory, we are informed of this and can react to it.
That's it.
Top comments (0)