我们几乎每天都在使用编辑器来开发程序,你会发现你在编辑器之外的地方修改了内容,或者新建了文件,编辑器中会实时自动更新;再比如,你打开一个目录,然后 ctrl+n 复制一个,此时你在其中一个窗口中创建文件,另一个窗口也会自动更新,所以说,文件系统的监控几乎无处不在。
在golang中,我们可以使用 fsnotify 来实现,它内部也是调用的操作系统提供的inotify
能力。它目前支持的平台
Adapter | OS | Status |
---|---|---|
inotify | Linux 2.6.27 or later, Android* | Supported |
kqueue | BSD, macOS, iOS* | Supported |
ReadDirectoryChangesW | Windows | Supported |
FSEvents | macOS | Planned |
FEN | Solaris 11 | In Progress |
fanotify | Linux 2.6.37+ | Planned |
USN Journals | Windows | Maybe |
Polling | All | Maybe |
fsnotify.go
package main
import (
"log"
"github.com/fsnotify/fsnotify"
)
func main() {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
done := make(chan bool)
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
log.Println("event:", event)
if event.Op&fsnotify.Write == fsnotify.Write {
log.Println("modified file:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("error:", err)
}
}
}()
err = watcher.Add("D:/dev/php/magook/trunk/server/golang/project/demo2")
if err != nil {
log.Fatal(err)
}
<-done
}
go run fsnotify.go
即可。
现代的操作系统都提供了文件系统的inotify
机制,它是基于事件通知以及回调的方式,比轮训的效率要高很多。
了解网络IO的多路复用机制的应该比较好理解,其内部实现思路也差不多,你可以将文件类比成连接,你可以使用 select, poll, epoll 的方式来监听,当文件或目录发生了增删改操作,就会返回对应的事件通知,以及处理相应的回调函数。