1 # File system notifications for Go |
1 fsnotify is a Go library to provide cross-platform filesystem notifications on |
|
2 Windows, Linux, macOS, and BSD systems. |
2 |
3 |
3 [![Go Reference](https://pkg.go.dev/badge/github.com/fsnotify/fsnotify.svg)](https://pkg.go.dev/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [![Maintainers Wanted](https://img.shields.io/badge/maintainers-wanted-red.svg)](https://github.com/fsnotify/fsnotify/issues/413) |
4 Go 1.16 or newer is required; the full documentation is at |
|
5 https://pkg.go.dev/github.com/fsnotify/fsnotify |
4 |
6 |
5 fsnotify utilizes [`golang.org/x/sys`](https://pkg.go.dev/golang.org/x/sys) rather than [`syscall`](https://pkg.go.dev/syscall) from the standard library. |
7 **It's best to read the documentation at pkg.go.dev, as it's pinned to the last |
|
8 released version, whereas this README is for the last development version which |
|
9 may include additions/changes.** |
6 |
10 |
7 Cross platform: Windows, Linux, BSD and macOS. |
11 --- |
8 |
12 |
9 | Adapter | OS | Status | |
13 Platform support: |
10 | --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | |
|
11 | inotify | Linux 2.6.27 or later, Android\* | Supported | |
|
12 | kqueue | BSD, macOS, iOS\* | Supported | |
|
13 | ReadDirectoryChangesW | Windows | Supported | |
|
14 | FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) | |
|
15 | FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) | |
|
16 | fanotify | Linux 2.6.37+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) | |
|
17 | USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) | |
|
18 | Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) | |
|
19 |
14 |
20 \* Android and iOS are untested. |
15 | Adapter | OS | Status | |
|
16 | --------------------- | ---------------| -------------------------------------------------------------| |
|
17 | inotify | Linux 2.6.32+ | Supported | |
|
18 | kqueue | BSD, macOS | Supported | |
|
19 | ReadDirectoryChangesW | Windows | Supported | |
|
20 | FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) | |
|
21 | FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) | |
|
22 | fanotify | Linux 5.9+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) | |
|
23 | USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) | |
|
24 | Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) | |
21 |
25 |
22 Please see [the documentation](https://pkg.go.dev/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information. |
26 Linux and macOS should include Android and iOS, but these are currently untested. |
23 |
27 |
24 ## API stability |
28 Usage |
25 |
29 ----- |
26 fsnotify is a fork of [howeyc/fsnotify](https://github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). |
30 A basic example: |
27 |
|
28 All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). |
|
29 |
|
30 ## Usage |
|
31 |
31 |
32 ```go |
32 ```go |
33 package main |
33 package main |
34 |
34 |
35 import ( |
35 import ( |
36 "log" |
36 "log" |
37 |
37 |
38 "github.com/fsnotify/fsnotify" |
38 "github.com/fsnotify/fsnotify" |
39 ) |
39 ) |
40 |
40 |
41 func main() { |
41 func main() { |
42 watcher, err := fsnotify.NewWatcher() |
42 // Create new watcher. |
43 if err != nil { |
43 watcher, err := fsnotify.NewWatcher() |
44 log.Fatal(err) |
44 if err != nil { |
45 } |
45 log.Fatal(err) |
46 defer watcher.Close() |
46 } |
|
47 defer watcher.Close() |
47 |
48 |
48 done := make(chan bool) |
49 // Start listening for events. |
49 go func() { |
50 go func() { |
50 for { |
51 for { |
51 select { |
52 select { |
52 case event, ok := <-watcher.Events: |
53 case event, ok := <-watcher.Events: |
53 if !ok { |
54 if !ok { |
54 return |
55 return |
55 } |
56 } |
56 log.Println("event:", event) |
57 log.Println("event:", event) |
57 if event.Op&fsnotify.Write == fsnotify.Write { |
58 if event.Has(fsnotify.Write) { |
58 log.Println("modified file:", event.Name) |
59 log.Println("modified file:", event.Name) |
59 } |
60 } |
60 case err, ok := <-watcher.Errors: |
61 case err, ok := <-watcher.Errors: |
61 if !ok { |
62 if !ok { |
62 return |
63 return |
63 } |
64 } |
64 log.Println("error:", err) |
65 log.Println("error:", err) |
65 } |
66 } |
66 } |
67 } |
67 }() |
68 }() |
68 |
69 |
69 err = watcher.Add("/tmp/foo") |
70 // Add a path. |
70 if err != nil { |
71 err = watcher.Add("/tmp") |
71 log.Fatal(err) |
72 if err != nil { |
72 } |
73 log.Fatal(err) |
73 <-done |
74 } |
|
75 |
|
76 // Block main goroutine forever. |
|
77 <-make(chan struct{}) |
74 } |
78 } |
75 ``` |
79 ``` |
76 |
80 |
77 ## Contributing |
81 Some more examples can be found in [cmd/fsnotify](cmd/fsnotify), which can be |
|
82 run with: |
78 |
83 |
79 Please refer to [CONTRIBUTING][] before opening an issue or pull request. |
84 % go run ./cmd/fsnotify |
80 |
85 |
81 ## FAQ |
86 FAQ |
|
87 --- |
|
88 ### Will a file still be watched when it's moved to another directory? |
|
89 No, not unless you are watching the location it was moved to. |
82 |
90 |
83 **When a file is moved to another directory is it still being watched?** |
91 ### Are subdirectories watched too? |
|
92 No, you must add watches for any directory you want to watch (a recursive |
|
93 watcher is on the roadmap: [#18]). |
84 |
94 |
85 No (it shouldn't be, unless you are watching where it was moved to). |
95 [#18]: https://github.com/fsnotify/fsnotify/issues/18 |
86 |
96 |
87 **When I watch a directory, are all subdirectories watched as well?** |
97 ### Do I have to watch the Error and Event channels in a goroutine? |
|
98 As of now, yes (you can read both channels in the same goroutine using `select`, |
|
99 you don't need a separate goroutine for both channels; see the example). |
88 |
100 |
89 No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]). |
101 ### Why don't notifications work with NFS, SMB, FUSE, /proc, or /sys? |
|
102 fsnotify requires support from underlying OS to work. The current NFS and SMB |
|
103 protocols does not provide network level support for file notifications, and |
|
104 neither do the /proc and /sys virtual filesystems. |
90 |
105 |
91 **Do I have to watch the Error and Event channels in a separate goroutine?** |
106 This could be fixed with a polling watcher ([#9]), but it's not yet implemented. |
92 |
107 |
93 As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7]) |
108 [#9]: https://github.com/fsnotify/fsnotify/issues/9 |
94 |
109 |
95 **Why am I receiving multiple events for the same file on OS X?** |
110 Platform-specific notes |
|
111 ----------------------- |
|
112 ### Linux |
|
113 When a file is removed a REMOVE event won't be emitted until all file |
|
114 descriptors are closed; it will emit a CHMOD instead: |
96 |
115 |
97 Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]). |
116 fp := os.Open("file") |
|
117 os.Remove("file") // CHMOD |
|
118 fp.Close() // REMOVE |
98 |
119 |
99 **How many files can be watched at once?** |
120 This is the event that inotify sends, so not much can be changed about this. |
100 |
121 |
101 There are OS-specific limits as to how many watches can be created: |
122 The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for |
102 * Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error. |
123 the number of watches per user, and `fs.inotify.max_user_instances` specifies |
103 * BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. |
124 the maximum number of inotify instances per user. Every Watcher you create is an |
|
125 "instance", and every path you add is a "watch". |
104 |
126 |
105 **Why don't notifications work with NFS filesystems or filesystem in userspace (FUSE)?** |
127 These are also exposed in `/proc` as `/proc/sys/fs/inotify/max_user_watches` and |
|
128 `/proc/sys/fs/inotify/max_user_instances` |
106 |
129 |
107 fsnotify requires support from underlying OS to work. The current NFS protocol does not provide network level support for file notifications. |
130 To increase them you can use `sysctl` or write the value to proc file: |
108 |
131 |
109 [#62]: https://github.com/howeyc/fsnotify/issues/62 |
132 # The default values on Linux 5.18 |
110 [#18]: https://github.com/fsnotify/fsnotify/issues/18 |
133 sysctl fs.inotify.max_user_watches=124983 |
|
134 sysctl fs.inotify.max_user_instances=128 |
|
135 |
|
136 To make the changes persist on reboot edit `/etc/sysctl.conf` or |
|
137 `/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your |
|
138 distro's documentation): |
|
139 |
|
140 fs.inotify.max_user_watches=124983 |
|
141 fs.inotify.max_user_instances=128 |
|
142 |
|
143 Reaching the limit will result in a "no space left on device" or "too many open |
|
144 files" error. |
|
145 |
|
146 ### kqueue (macOS, all BSD systems) |
|
147 kqueue requires opening a file descriptor for every file that's being watched; |
|
148 so if you're watching a directory with five files then that's six file |
|
149 descriptors. You will run in to your system's "max open files" limit faster on |
|
150 these platforms. |
|
151 |
|
152 The sysctl variables `kern.maxfiles` and `kern.maxfilesperproc` can be used to |
|
153 control the maximum number of open files. |
|
154 |
|
155 ### macOS |
|
156 Spotlight indexing on macOS can result in multiple events (see [#15]). A temporary |
|
157 workaround is to add your folder(s) to the *Spotlight Privacy settings* until we |
|
158 have a native FSEvents implementation (see [#11]). |
|
159 |
111 [#11]: https://github.com/fsnotify/fsnotify/issues/11 |
160 [#11]: https://github.com/fsnotify/fsnotify/issues/11 |
112 [#7]: https://github.com/howeyc/fsnotify/issues/7 |
161 [#15]: https://github.com/fsnotify/fsnotify/issues/15 |
113 |
|
114 [contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md |
|
115 |
|
116 ## Related Projects |
|
117 |
|
118 * [notify](https://github.com/rjeczalik/notify) |
|
119 * [fsevents](https://github.com/fsnotify/fsevents) |
|
120 |
|