Golang fsnotify 在 Windows 上为同一个文件发送多个事件

Posted

技术标签:

【中文标题】Golang fsnotify 在 Windows 上为同一个文件发送多个事件【英文标题】:Golang fsnotify sends multiple events for same file on Windows 【发布时间】:2019-02-11 10:17:32 【问题描述】:

我正在编写一个简单的 golang 脚本来监控 Windows 上的下载文件夹。这个想法是,每当下载新文件时,它将被发送到打印机。这主要按预期工作。代码如下:

package main

import (
    "log"
    "fmt"
    "github.com/howeyc/fsnotify"
    "os/exec"
)

func main() 
    watcher, err := fsnotify.NewWatcher()
    if err != nil 
        log.Fatal(err)
    

    done := make(chan bool)

    // Process events
    go func() 
        for 
            select 
            case ev := <-watcher.Event:
                log.Println("event:", ev)
                c := exec.Command("cmd", "/C", "RawFileToPrinter.exe", ev.Name)
                if err := c.Run(); err != nil 
                    fmt.Println("Error: ", err)
                

            case err := <-watcher.Error:
                log.Println("error:", err)
            
        
    ()

    err = watcher.Watch("C:\\Users\\admin\\Downloads")
    if err != nil 
        log.Fatal(err)
    

    // Hang so program doesn't exit
    <-done

    /* ... do stuff ... */
    watcher.Close()

不幸的是,我发现为同一个文件发送了多个事件,如以下日志所示:

2019/02/11 15:34:26 event: "C:\\Users\\admin\\Downloads\\0fcc8a09-9c51-4c5e-a77c-d4f111f6931f.tmp": CREATE
(*fsnotify.FileEvent)(0x10e821c0)("C:\\Users\\admin\\Downloads\\0fcc8a09-9c51-4c5e-a77c-d4f111f6931f.tmp": CREATE)
2019/02/11 15:34:37 event: "C:\\Users\\admin\\Downloads\\0fcc8a09-9c51-4c5e-a77c-d4f111f6931f.tmp": MODIFY
(*fsnotify.FileEvent)(0x10e821d0)("C:\\Users\\admin\\Downloads\\0fcc8a09-9c51-4c5e-a77c-d4f111f6931f.tmp": MODIFY)
2019/02/11 15:34:40 event: "C:\\Users\\admin\\Downloads\\0fcc8a09-9c51-4c5e-a77c-d4f111f6931f.tmp": RENAME
(*fsnotify.FileEvent)(0x10e821e0)("C:\\Users\\admin\\Downloads\\0fcc8a09-9c51-4c5e-a77c-d4f111f6931f.tmp": RENAME)
2019/02/11 15:34:41 event: "C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt.crdownload": RENAME
(*fsnotify.FileEvent)(0x10e821f0)("C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt.crdownload": RENAME)
2019/02/11 15:34:42 event: "C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt.crdownload": RENAME
(*fsnotify.FileEvent)(0x10e82200)("C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt.crdownload": RENAME)
2019/02/11 15:34:44 event: "C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt": RENAME
(*fsnotify.FileEvent)(0x10e82210)("C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt": RENAME)
2019/02/11 15:34:46 event: "C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt": MODIFY
(*fsnotify.FileEvent)(0x10e82220)("C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt": MODIFY)
2019/02/11 15:34:47 event: "C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt": MODIFY
(*fsnotify.FileEvent)(0x10e82230)("C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt": MODIFY)
2019/02/11 15:34:48 event: "C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt": MODIFY
(*fsnotify.FileEvent)(0x10e82240)("C:\\Users\\admin\\Downloads\\Generico-Bill-MULW-132482.txt": MODIFY)

这会导致多次打印同一个文件。 exe 忽略 *.tmp 和 *.crdownload。是否有可能获得单个事件?如果不是,我该如何处理这种情况?

【问题讨论】:

如果你注释掉case ev := &lt;-watcher.Event:分支中除log.Println之外的所有代码,问题是否仍然存在? 【参考方案1】:

首先:*fsnotify.FileEvent 表示您使用的是旧版本的 fsnotify 包,请将您的依赖项更改为:github.com/fsnotify/fsnotify

我没有要测试的 Windows 机器,所以我不能保证这会解决您的问题。但在我看来,后来的文件修改是属性更改。

只看重命名为 *.tmp 和 *.crdownload 应该足以打印您的文件,因为您的 RawFileToPrinter.exe 不应该关心文件是从 Internet 下载的或之后设置的任何属性完成下载。

【讨论】:

以上是关于Golang fsnotify 在 Windows 上为同一个文件发送多个事件的主要内容,如果未能解决你的问题,请参考以下文章

fsnotify 文件系统通知

fsnotify 文件系统通知

在fsnotify上递归重新生成文件删除/重命名(Golang)

FSNotify 在运行时添加监视目录

Go 每日一库之 fsnotify

[Go] 跨平台文件系统监控工具 fsnotify 应用举例