fsnotify is a file system notification library written in Go, which can monitor changes to files and directories in the file system and notify the application when changes occur. It supports cross-platform operation and can run on different operating systems such as Linux, macOS, and Windows. fsnotify utilizes the file system notification mechanisms of different operating systems, such as inotify on Linux, FSEvents on macOS, and ReadDirectoryChangesW on Windows.
Requires the use of Go 1.17 or later versions; complete documentation can be found at https://pkg.go.dev/github.com/fsnotify/fsnotify
Support for different operating systems:
Backend | Operating System | Status |
---|---|---|
inotify | Linux | Supported |
kqueue | BSD, macOS | Supported |
ReadDirectoryChangesW | Windows | Supported |
FEN | illumos | Supported |
fanotify | Linux 5.9+ | Not yet supported |
AHAFS | AIX | AIX branch; Experimental feature due to lack of maintainers and test environment |
FSEvents | macOS | Requires x/sys/unix support |
USN Journals | Windows | Requires x/sys/windows support |
Polling | All | Not yet supported |
Android and Solaris, which should include Linux and illumos, have not been tested yet.
Use Cases
The use cases of fsnotify include but are not limited to the following situations:
- Real-time file synchronization: fsnotify can monitor changes in the file system in real time, making it suitable for implementing real-time file synchronization. When changes occur in the source file, the changes can be immediately synchronized to the target file, ensuring consistency of the files.
- Automated building: fsnotify can monitor changes in the project's source code and dependency files, triggering build commands when changes occur, thereby achieving automated building. This can save time and effort of manual building and improve development efficiency.
- File backup: fsnotify can monitor changes to files or directories that need to be backed up and initiate immediate backup when changes occur. This ensures the security of data and prevents data loss due to file loss or damage.
- Real-time log monitoring: fsnotify can monitor operations such as creation, modification, and deletion of log files, triggering log monitoring programs when changes occur in log files, effectively monitoring changes in log content in real time.
- File system security monitoring: fsnotify can monitor security events in the file system, such as file access, modification, and deletion. This allows for security monitoring of the file system, promptly identifying and recording insecure events.
Usage Example
A basic example:
package main
import (
"log"
"github.com/fsnotify/fsnotify"
)
func main() {
// Create a new watcher.
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// Start listening for events.
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
log.Println("Event:", event)
if event.Has(fsnotify.Write) {
log.Println("Modified file:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("Error:", err)
}
}
}()
// Add the path that needs to be monitored.
err = watcher.Add("/tmp")
if err != nil {
log.Fatal(err)
}
// Block the main goroutine.
<-make(chan struct{})
}
More examples can be found in cmd/fsnotify and can be run using the following command:
% go run ./cmd/fsnotify
More detailed documentation can be found in godoc: https://pkg.go.dev/github.com/fsnotify/fsnotify
Frequently Asked Questions
Will it still be monitored if the file is moved to another directory?
No, unless you are monitoring the location it is moved to.
Does it monitor subdirectories?
No, you must add monitoring for each directory you want to monitor (recursive monitoring is planned: #18).
Do I need to monitor both the error and event channels in a goroutine simultaneously?
Yes. You can use select
to read from both channels in the same goroutine (you don't need to start a goroutine separately for each channel; see the example).
Why do notifications not work on NFS, SMB, FUSE, /proc, or /sys?
fsnotify requires support from the underlying operating system to function. The current NFS and SMB protocols do not provide network-level support for file notifications, and the /proc and /sys virtual file systems also do not provide support.
This could be fixed by using a polling watcher (#9), but it has not been implemented yet.
Why am I receiving many Chmod events?
Some programs may generate a large number of attribute changes, such as Spotlight on macOS, antivirus programs, backup applications, and some other known applications. In general, ignoring Chmod events is usually the best practice as they are often useless and may cause issues.
Spotlight indexing on macOS may cause multiple events (see #15). A temporary solution is to add your folders to Spotlight Privacy Settings until we have a native FSEvents implementation (see #11).
Watching files doesn't work well
It is generally not recommended to watch individual files (rather than directories) because many programs, especially editors, will atomically update files: it will write to a temporary file and then move it to the target location, overwriting the original file (or some variant of it). The monitor on the original file is now lost because the file no longer exists.
As a result, a power failure or a crash will not result in a half-written file.
Watch the parent directory and use Event.Name
to filter out the files you are not interested in. There is an example in cmd/fsnotify/file.go
.
Notes for Specific Platforms
Linux
When a file is deleted, the REMOVE event will not be issued until all file descriptors are closed; at this time, a CHMOD event will be issued:
fp := os.Open("file")
os.Remove("file") // CHMOD
fp.Close() // REMOVE
This is the event sent by inotify, so there should not be too many changes made to it.
The fs.inotify.max_user_watches
sysctl variable specifies the maximum number of watches per user, and fs.inotify.max_user_instances
specifies the maximum number of inotify instances per user. Each Watcher you create is an "instance," and each path you add is a "watch".
These can also be found in /proc
, with the paths /proc/sys/fs/inotify/max_user_watches
and /proc/sys/fs/inotify/max_user_instances
.
To increase them, you can use sysctl
or write the values to the proc file:
sysctl fs.inotify.max_user_watches=124983
sysctl fs.inotify.max_user_instances=128
To make the changes take effect after a reboot, edit /etc/sysctl.conf
or /usr/lib/sysctl.d/50-default.conf
(the details may vary for each Linux distribution, please refer to your distribution's documentation):
fs.inotify.max_user_watches=124983
fs.inotify.max_user_instances=128
Reaching the limit will result in "No space left on device" or "Too many open files" errors.
kqueue (macOS, all BSD systems)
kqueue requires opening a file descriptor for each observed file; therefore, if you are observing a directory containing five files, that's six file descriptors. On these platforms, you will reach the system's "maximum open files" limit more quickly.
You can use the sysctl variables kern.maxfiles
and kern.maxfilesperproc
to control the maximum number of open files.