繁体   English   中英

使用 FileSystemWatcher 检测移动的文件

[英]Detecting moved files using FileSystemWatcher

我意识到 FileSystemWatcher 不提供 Move 事件,而是会为同一文件生成单独的 Delete 和 Create 事件。 (FilesystemWatcher 正在监视源文件夹和目标文件夹)。

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

FileSystemEventArgs 类的某种属性,如“AssociatedDeleteFile”,如果它是移动的结果,则分配删除的文件路径,否则为 NULL,这将是很好的。 但这当然不存在。

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

根据反馈更新:

FileSystemWatcher 类似乎将移动文件视为两个不同的事件,一个是删除原始文件,另一个是在新位置创建。

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

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

根据文档

常见的文件系统操作可能引发不止一个事件。 例如,当文件从一个目录移动到另一个目录时,可能会引发多个 OnChanged 事件以及一些 OnCreated 和 OnDeleted 事件。 移动文件是一项复杂的操作,由多个简单操作组成,因此会引发多个事件。

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

据我了解, Renamed事件用于移动文件......?

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

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

它还说关于移动文件:

常见的文件系统操作可能引发不止一个事件。 例如,当文件从一个目录移动到另一个目录时,可能会引发多个 OnChanged 事件以及一些 OnCreated 和 OnDeleted 事件。 移动文件是一项复杂的操作,由多个简单操作组成,因此会引发多个事件。

正如您已经提到的,没有可靠的方法可以使用 C# 提供的默认 FileSystemWatcher 类来执行此操作。 您可以应用某些启发式方法,如文件名、哈希或唯一文件 ID来将创建和删除的事件映射在一起,但这些方法都不能可靠地工作。 此外,您无法轻易获得与已删除事件关联的文件的哈希值或文件 ID,这意味着您必须在某种数据库中维护这些值。

我认为检测文件移动的唯一可靠方法是创建一个自己的文件系统观察器。 因此,您可以使用不同的方法。 如果您只想查看 NTFS 文件系统上的更改,一种解决方案可能是按此处所述读出 NTFS 更改日志。 这样做的好处在于,它甚至允许您跟踪应用程序未运行时发生的更改。

另一种方法是创建一个 minifilter 驱动程序来跟踪文件系统操作并将它们转发给您的应用程序。 使用它,您基本上可以获得有关文件发生情况的所有信息,并且您将能够获得有关移动文件的信息。 这种方法的一个缺点是您必须创建一个需要安装在目标系统上的单独驱动程序。 然而,好处是你不需要从头开始,因为我已经开始创建这样的东西: 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 上运行(如果您不禁用签名检查以进行测试)。 在撰写本文时,这段代码还处于开发的早期阶段,所以我还不会在生产系统上使用它。 但即使您不打算使用它,它仍应为您提供一些有关如何在 Windows 上跟踪文件系统事件的信息。

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

您是否遇到过随机文件创建影响移动检测的情况?

可能想尝试文档中提到的 OnChanged 和/或 OnRenamed 事件。

StorageLibrary 类可以跟踪移动 来自微软的例子:

StorageLibrary videosLib = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Videos);
StorageLibraryChangeTracker videoTracker = videosLib.ChangeTracker;
videoTracker.Enable();

可以在此处找到完整示例。 但是,看起来您只能跟踪 Windows“ 已知库”中的更改。

您还可以尝试使用StorageFolder.TryGetChangeTracker()获取 StorageLibraryChangeTracker。 但是你的文件夹必须在sync root下,你不能用这个方法获取文件系统中的任意文件夹。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM