162 lines
5.6 KiB
Markdown
162 lines
5.6 KiB
Markdown
fsnotify is a Go library to provide cross-platform filesystem notifications on
|
|
Windows, Linux, macOS, and BSD systems.
|
|
|
|
Go 1.16 or newer is required; the full documentation is at
|
|
https://pkg.go.dev/github.com/fsnotify/fsnotify
|
|
|
|
**It's best to read the documentation at pkg.go.dev, as it's pinned to the last
|
|
released version, whereas this README is for the last development version which
|
|
may include additions/changes.**
|
|
|
|
---
|
|
|
|
Platform support:
|
|
|
|
| Adapter | OS | Status |
|
|
| --------------------- | ---------------| -------------------------------------------------------------|
|
|
| inotify | Linux 2.6.32+ | Supported |
|
|
| kqueue | BSD, macOS | Supported |
|
|
| ReadDirectoryChangesW | Windows | Supported |
|
|
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
|
|
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) |
|
|
| fanotify | Linux 5.9+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) |
|
|
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
|
|
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
|
|
|
|
Linux and macOS should include Android and iOS, but these are currently untested.
|
|
|
|
Usage
|
|
-----
|
|
A basic example:
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"log"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
)
|
|
|
|
func main() {
|
|
// Create 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 a path.
|
|
err = watcher.Add("/tmp")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Block main goroutine forever.
|
|
<-make(chan struct{})
|
|
}
|
|
```
|
|
|
|
Some more examples can be found in [cmd/fsnotify](cmd/fsnotify), which can be
|
|
run with:
|
|
|
|
% go run ./cmd/fsnotify
|
|
|
|
FAQ
|
|
---
|
|
### Will a file still be watched when it's moved to another directory?
|
|
No, not unless you are watching the location it was moved to.
|
|
|
|
### Are subdirectories watched too?
|
|
No, you must add watches for any directory you want to watch (a recursive
|
|
watcher is on the roadmap: [#18]).
|
|
|
|
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
|
|
|
### Do I have to watch the Error and Event channels in a goroutine?
|
|
As of now, yes (you can read both channels in the same goroutine using `select`,
|
|
you don't need a separate goroutine for both channels; see the example).
|
|
|
|
### Why don't notifications work with NFS, SMB, FUSE, /proc, or /sys?
|
|
fsnotify requires support from underlying OS to work. The current NFS and SMB
|
|
protocols does not provide network level support for file notifications, and
|
|
neither do the /proc and /sys virtual filesystems.
|
|
|
|
This could be fixed with a polling watcher ([#9]), but it's not yet implemented.
|
|
|
|
[#9]: https://github.com/fsnotify/fsnotify/issues/9
|
|
|
|
Platform-specific notes
|
|
-----------------------
|
|
### Linux
|
|
When a file is removed a REMOVE event won't be emitted until all file
|
|
descriptors are closed; it will emit a CHMOD instead:
|
|
|
|
fp := os.Open("file")
|
|
os.Remove("file") // CHMOD
|
|
fp.Close() // REMOVE
|
|
|
|
This is the event that inotify sends, so not much can be changed about this.
|
|
|
|
The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for
|
|
the number of watches per user, and `fs.inotify.max_user_instances` specifies
|
|
the maximum number of inotify instances per user. Every Watcher you create is an
|
|
"instance", and every path you add is a "watch".
|
|
|
|
These are also exposed in `/proc` as `/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 value to proc file:
|
|
|
|
# The default values on Linux 5.18
|
|
sysctl fs.inotify.max_user_watches=124983
|
|
sysctl fs.inotify.max_user_instances=128
|
|
|
|
To make the changes persist on reboot edit `/etc/sysctl.conf` or
|
|
`/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your
|
|
distro's documentation):
|
|
|
|
fs.inotify.max_user_watches=124983
|
|
fs.inotify.max_user_instances=128
|
|
|
|
Reaching the limit will result in a "no space left on device" or "too many open
|
|
files" error.
|
|
|
|
### kqueue (macOS, all BSD systems)
|
|
kqueue requires opening a file descriptor for every file that's being watched;
|
|
so if you're watching a directory with five files then that's six file
|
|
descriptors. You will run in to your system's "max open files" limit faster on
|
|
these platforms.
|
|
|
|
The sysctl variables `kern.maxfiles` and `kern.maxfilesperproc` can be used to
|
|
control the maximum number of open files.
|
|
|
|
### macOS
|
|
Spotlight indexing on macOS can result in multiple events (see [#15]). A temporary
|
|
workaround is to add your folder(s) to the *Spotlight Privacy settings* until we
|
|
have a native FSEvents implementation (see [#11]).
|
|
|
|
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
|
[#15]: https://github.com/fsnotify/fsnotify/issues/15
|