golang,go,博客,开源,编程
fsnotify/fsnotify
是一个 Go 语言库,用于监控文件系统中的变化,包括文件和目录的修改、删除、创建等。这个库非常适合用于实现文件监控功能,例如日志文件监控、配置文件热加载、文件同步等应用场景。
使用 go get
命令安装 fsnotify
库:
go get github.com/fsnotify/fsnotify
fsnotify
库底层会根据操作系统的不同,选择不同的方式来监听文件变化。对于 Linux,使用 inotify
,对于 macOS,使用 kqueue
,对于 Windows,使用 ReadDirectoryChangesW
。Event
发送到事件通道,你可以通过通道来接收和处理这些事件。fsnotify
中定义了多个文件事件类型,常用的有以下几种:
fsnotify.Create
:文件或目录被创建。fsnotify.Remove
:文件或目录被删除。fsnotify.Rename
:文件或目录被重命名。fsnotify.Write
:文件内容被写入。fsnotify.Chmod
:文件权限被修改。下面是一个基本的示例,展示了如何使用 fsnotify
来监听文件或目录的变化。
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"log"
"time"
)
func main() {
// 创建一个新的 watcher
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// 监控当前目录
dir := "."
err = watcher.Add(dir)
if err != nil {
log.Fatal(err)
}
// 事件处理
go func() {
for {
select {
case event := <-watcher.Events:
fmt.Println("Event:", event)
// 检查文件/目录创建事件
if event.Op&fsnotify.Create == fsnotify.Create {
fmt.Println("File created:", event.Name)
}
// 检查文件/目录删除事件
if event.Op&fsnotify.Remove == fsnotify.Remove {
fmt.Println("File removed:", event.Name)
}
// 检查文件修改事件
if event.Op&fsnotify.Write == fsnotify.Write {
fmt.Println("File modified:", event.Name)
}
case err := <-watcher.Errors:
fmt.Println("Error:", err)
}
}
}()
// 模拟一些文件操作
time.Sleep(2 * time.Second)
fmt.Println("Creating file test.txt...")
_, err = createFile("test.txt")
if err != nil {
log.Fatal(err)
}
time.Sleep(2 * time.Second)
fmt.Println("Deleting file test.txt...")
err = deleteFile("test.txt")
if err != nil {
log.Fatal(err)
}
// 保持程序运行
select {}
}
func createFile(filename string) (*os.File, error) {
return os.Create(filename)
}
func deleteFile(filename string) error {
return os.Remove(filename)
}
fsnotify.NewWatcher()
:创建一个新的文件监视器。watcher.Add(dir)
:添加需要监视的目录(或文件)。watcher.Events
:这是一个通道,接收文件系统的事件(例如文件创建、删除等)。watcher.Errors
:这是一个通道,接收错误信息。event.Op
:表示文件操作的类型,例如创建、删除、写入等。在上面的代码中,我们监控当前目录的变化,并模拟了一个文件的创建和删除操作。程序会输出文件系统事件,指示文件的创建、删除和修改。
fsnotify
支持同时监视多个文件或目录,只需多次调用 watcher.Add()
即可。
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"log"
"os"
"time"
)
func main() {
// 创建一个新的 watcher
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// 添加多个文件和目录
err = watcher.Add("dir1")
if err != nil {
log.Fatal(err)
}
err = watcher.Add("dir2")
if err != nil {
log.Fatal(err)
}
// 事件处理
go func() {
for {
select {
case event := <-watcher.Events:
fmt.Println("Event:", event)
case err := <-watcher.Errors:
fmt.Println("Error:", err)
}
}
}()
// 模拟一些文件操作
time.Sleep(2 * time.Second)
createFile("dir1/test1.txt")
time.Sleep(2 * time.Second)
createFile("dir2/test2.txt")
// 保持程序运行
select {}
}
func createFile(filename string) {
file, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
file.Close()
}
在这个示例中,我们添加了两个目录 dir1
和 dir2
来监控它们的变化。如果 dir1
或 dir2
中的文件发生变化,事件通道就会接收到事件。
你可以根据文件操作类型过滤事件,比如仅监听文件创建或修改事件。
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"log"
"os"
"time"
)
func main() {
// 创建一个新的 watcher
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// 监控当前目录
dir := "."
err = watcher.Add(dir)
if err != nil {
log.Fatal(err)
}
// 事件处理
go func() {
for {
select {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
fmt.Println("File modified:", event.Name)
}
case err := <-watcher.Errors:
fmt.Println("Error:", err)
}
}
}()
// 模拟文件操作
time.Sleep(2 * time.Second)
createFile("test.txt")
time.Sleep(2 * time.Second)
writeToFile("test.txt")
// 保持程序运行
select {}
}
func createFile(filename string) {
file, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
file.Close()
}
func writeToFile(filename string) {
file, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, os.ModePerm)
if err != nil {
log.Fatal(err)
}
defer file.Close()
file.WriteString("Hello, fsnotify!\n")
}
在这个例子中,我们只对 fsnotify.Write
事件感兴趣,因此只在文件被修改时打印消息。
fsnotify
可能会错过一些事件。为了避免丢失事件,您可以结合定时器定期扫描文件状态。ulimit -n
查看并设置文件句柄数量。fsnotify
是一个非常有用的 Go 库,它基于操作系统的原生文件系统监控机制,能够高效地处理文件系统变化的通知。通过它,你可以轻松地实现文件变化监控、自动重载、日志监控等功能。该库支持多平台,可以广泛应用于文件同步、热更新等各种场景。