代码之家  ›  专栏  ›  技术社区  ›  Ash

使用FileSystemWatcher检测移动的文件

  •  18
  • Ash  · 技术社区  · 15 年前

    我认识到FileSystemWatcher不提供移动事件,而是为同一个文件生成单独的删除和创建事件。(FileSystemWatcher同时监视源文件夹和目标文件夹)。

    但是,我们如何区分真正的文件移动和随机创建的文件恰好与最近删除的文件同名?

    filesystemEventargs类的某些属性,例如“associateddeletefile”,如果是移动的结果,则会为其分配已删除的文件路径,否则为空,这将是很好的选择。但这当然不存在。

    我还了解FileSystemWatcher是在基本的文件系统级别上运行的,因此“移动”的概念可能只对更高级别的应用程序有意义。但是如果是这样的话,在我的应用程序中,人们会推荐哪种算法来处理这种情况?

    根据反馈更新:

    FileSystemWatcher类似乎只将文件移动为两个不同的事件,即删除原始文件,然后在新位置创建。

    不幸的是,这些事件之间没有提供“链接”,因此如何区分文件移动和正常的删除或创建并不明显。在操作系统级别,移动是经过特殊处理的,您几乎可以瞬间移动一个1GB文件。

    一些答案建议使用散列文件在事件之间可靠地识别它们,我很乐意采用这种方法。但如果有人知道如何更简单地检测移动,请留下答案。

    5 回复  |  直到 6 年前
        1
  •  11
  •   InteXX    6 年前

    根据 docs :

    常见的文件系统操作可能 引发多个事件。用于 例如,当文件从一个 目录到另一个,多个 一个被绞死的和一些被绞死的 可能会引发未删除的事件。 移动文件是一项复杂的操作 由多个简单的 操作,因此提高了 事件。

    因此,如果你试图非常小心地检测移动,并且拥有相同的路径还不够好,你将不得不使用某种启发式方法。例如,使用文件名、大小、上次修改时间等为源文件夹中的文件创建“指纹”。当您看到任何可能表示移动的事件时,请对照新文件检查“指纹”。

        2
  •  3
  •   Aviad Ben Dov    15 年前

    据我所知, Renamed 事件用于正在移动的文件…?

    我的错误-文档特别指出,在剪切和粘贴操作中,只有移动文件夹中的文件才被视为“重命名”:

    操作系统和FileSystemWatcher对象将剪切粘贴操作或移动操作解释为文件夹及其内容的重命名操作。如果将文件所在的文件夹剪切并粘贴到正在监视的文件夹中,则FileSystemWatcher对象只报告该文件夹为新文件夹,而不报告其内容,因为它们本质上只是重命名的。

    它还提到移动文件:

    通用文件系统操作可能引发多个事件。例如,当文件从一个目录移动到另一个目录时,可能会引发几个onchanged和一些oncreated和ondeleted事件。移动文件是一个复杂的操作,由多个简单操作组成,因此引发多个事件。

        3
  •  2
  •   Noon Silk    15 年前

    我会冒险猜测“移动”确实不存在,所以你只需要查找“删除”,然后将该文件标记为“可能移动”的文件,然后如果你在不久后看到“创建”,我想你可以假定你是正确的。

    你是否有一个随机文件创建的案例影响你的移动检测?

        4
  •  2
  •   andymeadows    15 年前

    可能要尝试中提到的onChanged和/或onRename事件 the documentation .

        5
  •  2
  •   Community    7 年前

    正如您已经提到的,对于C提供的默认filesystemwatcher类,没有可靠的方法可以做到这一点。您可以应用某些启发式方法,如文件名、哈希或 unique file ids 将已创建和已删除的事件映射在一起,但这些方法都不能可靠地工作。此外,您无法轻松获取与已删除事件关联的文件的哈希或文件ID,这意味着您必须在某种类型的数据库中维护这些值。

    我认为检测文件移动的唯一可靠方法是创建一个自己的文件系统监视程序。因此,您可以使用不同的方法。如果您只想查看NTFS文件系统上的更改,一种解决方案可能是按照说明读取NTFS更改日志。 here . 它的好处在于,它甚至允许你跟踪在应用程序不运行时发生的更改。

    另一种方法是创建一个微过滤器驱动程序,跟踪文件系统操作并将其转发到应用程序。使用这个,你基本上可以得到关于你的文件发生了什么的所有信息,并且你可以得到关于移动文件的信息。这种方法的一个缺点是,您必须创建一个需要安装在目标系统上的单独驱动程序。但好的是,你不需要从头开始,因为我已经开始创建类似这样的东西: https://github.com/CenterDevice/MiniFSWatcher

    这允许您简单地跟踪移动的文件,如下所示:

    var eventWatcher = new EventWatcher();
    
    eventWatcher.OnRenameOrMove += (filename, oldFilename, process) =>
    {
      Console.WriteLine("File " + oldFilename + " has been moved to " + filename + " by process " + process );
    };
    
    eventWatcher.Connect();
    eventWatcher.WatchPath("C:\\Users\\MyUser\\*");
    

    但是,请注意,这需要对内核代码进行签名,以便在64位版本的Windows上运行(如果您没有 disable 签名检查测试)。在编写时,这个代码还处于开发的早期阶段,所以我会 在生产系统中使用它。但即使您不打算使用它,它仍然应该提供一些关于如何在Windows上跟踪文件系统事件的信息。