23

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

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

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

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

根据反馈更新:

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

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

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

4

6 回答 6

14

根据文档

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

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

于 2009-08-17T04:22:38.287 回答
4

据我了解,该Renamed事件是针对正在移动的文件...?

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

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

它还谈到了移动文件:

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

于 2009-08-17T04:15:32.870 回答
4

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

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

另一种方法是创建一个微过滤驱动程序来跟踪文件系统操作并将它们转发到您的应用程序。使用它,您基本上可以获得有关文件发生情况的所有信息,并且您将能够获得有关移动文件的信息。这种方法的一个缺点是您必须创建一个需要安装在目标系统上的单独驱动程序。然而,好消息是你不需要从头开始,因为我已经开始创建这样的东西: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 上跟踪文件系统事件的信息。

于 2016-05-18T11:25:29.493 回答
2

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

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

于 2009-08-17T04:13:11.470 回答
2

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

于 2009-08-17T04:17:53.897 回答
0

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

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

一个完整的例子可以在这里找到。但是,您似乎只能跟踪 Windows“已知库”中的更改。

您还可以尝试使用StorageFolder.TryGetChangeTracker()获取 StorageLibraryChangeTracker 。但是你的文件夹必须在同步根目录下,你不能使用这种方法来获取文件系统中的任意文件夹。

于 2020-08-24T00:09:26.657 回答