Golang 监控文件夹内文件的增删改(包括子文件夹)

你需要自己处理log部分

package main

import (
    "crypto/md5"
    "fmt"
    "go-admin/log"
    "os"
    "path/filepath"
    "time"

    "github.com/fsnotify/fsnotify"
)

type FileChangeCallback func(absfpname string)

type ConfigFileWatcher struct {
    WatchedDirectory string             // 监控目录
    FileSuffix       string             // 监控的文件类型
    OnFileChange     FileChangeCallback // 相关文件有变更就会调用这个回调
}

func (cfw ConfigFileWatcher) WatchConfigFileChanges() {
    // 注意如果该文件被其他程序占用的话会读取不出内容的。比如vscode打开了文件
    getFileHash := func(filename string) (string, error) {
        data, err := os.ReadFile(filename)
        if err != nil {
            return "", err
        }
        return fmt.Sprintf("%x", md5.Sum(data)), nil
    }

    watcher, err := fsnotify.NewWatcher()
    if err != nil {
        log.Fatal("WatchConfigFileChanges", err.Error(), "")
    }
    defer watcher.Close()

    dir := cfw.WatchedDirectory

    fileInfos := make(map[string]string)

    err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }
        if info.IsDir() {
            err = watcher.Add(path)
            if err != nil {
                log.Fatal("WatchConfigFileChanges", err.Error(), "")
            }
        } else {
            if filepath.Ext(path) == ".yml" {
                hash, err := getFileHash(path)
                if err != nil {
                    log.Fatal("WatchConfigFileChanges", "获取文件哈希出错:%s", err.Error())
                } else {
                    fileInfos[path] = hash
                }
            }

        }
        return nil
    })
    if err != nil {
        log.Fatal("WatchConfigFileChanges", "%s", err.Error())

    }

    fmt.Println("开始监控...")

    var lastEventTime time.Time
    interval := 500 * time.Millisecond // 设置等待时间为500毫秒

    func() {
        for {
            select {
            case event, ok := <-watcher.Events:
                if !ok {
                    return
                }
                if (event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create) &&
                    filepath.Ext(event.Name) == cfw.FileSuffix {

                    // 检查时间间隔,如果在等待时间内则跳过
                    if time.Since(lastEventTime) < interval {
                        continue
                    }

                    // 获取文件的最新MD5值
                    newHash, err := getFileHash(event.Name)
                    if err != nil {
                        log.Fatal("WatchConfigFileChanges", "获取文件哈希出错:%s", err.Error())
                    } else {
                        // 对比MD5值,确认文件内容是否发生了变化
                        if prevHash, exists := fileInfos[event.Name]; exists && prevHash == newHash {
                            fmt.Println("文件未更改:", event.Name)
                            log.Log("WatchConfigFileChanges", "文件未更改:%s", event.Name)
                        } else {
                            fileInfos[event.Name] = newHash
                            absPath, _ := filepath.Abs(event.Name)
                            log.Log("WatchConfigFileChanges", "文件修改或创建:%s", absPath)
                            cfw.OnFileChange(absPath)
                        }
                    }

                    // 更新最后事件时间
                    lastEventTime = time.Now()

                    // 因为fsnotify源码常量定义错了。Rename和Remove搞反了
                } else if (event.Op&fsnotify.Rename == fsnotify.Rename) && filepath.Ext(event.Name) == cfw.FileSuffix {
                    // 检查时间间隔,如果在等待时间内则跳过
                    if time.Since(lastEventTime) < interval {
                        continue
                    }
                    absPath, _ := filepath.Abs(event.Name)
                    fmt.Println("文件被删除:", absPath)
                    cfw.OnFileChange(absPath)
                    // 更新最后事件时间
                    lastEventTime = time.Now()
                }
            case err, ok := <-watcher.Errors:
                if !ok {
                    return
                }
                log.Fatal("WatchConfigFileChanges", "错误:%s", err.Error())
            }
        }
    }()

}

 

posted @ 2024-01-11 09:06  看一百次夜空里的深蓝  阅读(292)  评论(0编辑  收藏  举报