使用 FileSystemWatcher 检测移动的文件

发布于 2024-08-02 05:29:55 字数 606 浏览 9 评论 0 原文

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

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

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

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

根据反馈进行更新:

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

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

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

I realise that FileSystemWatcher does not provide a Move event, instead it will generate a separate Delete and Create events for the same file. (The FilesystemWatcher is watching both the source and destination folders).

However how do we differentiate between a true file move and some random creation of a file that happens to have the same name as a file that was recently deleted?

Some sort of property of the FileSystemEventArgs class such as "AssociatedDeleteFile" that is assigned the deleted file path if it is the result of a move, or NULL otherwise, would be great. But of course this doesn't exist.

I also understand that the FileSystemWatcher is operating at the basic Filesystem level and so the concept of a "Move" may be only meaningful to higher level applications. But if this is the case, what sort of algorithm would people recommend to handle this situation in my application?

Update based on feedback:

The FileSystemWatcher class seems to see moving a file as simply 2 distinct events, a Delete of the original file, followed by a Create at the new location.

Unfortunately there is no "link" provided between these events, so it is not obvious how to differentiate between a file move and a normal Delete or Create. At the OS level, a move is treated specially, you can move say a 1GB file almost instantaneously.

A couple of answers suggested using a hash on files to identify them reliably between events, and I will proably take this approach. But if anyone knows how to detect a move more simply, please leave an answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

段念尘 2024-08-09 05:29:55

根据 文档

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

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

According to the docs:

Common file system operations might
raise more than one event. For
example, when a file is moved from one
directory to another, several
OnChanged and some OnCreated and
OnDeleted events might be raised.
Moving a file is a complex operation
that consists of multiple simple
operations, therefore raising multiple
events.

So if you're trying to be very careful about detecting moves, and having the same path is not good enough, you will have to use some sort of heuristic. For example, create a "fingerprint" using file name, size, last modified time, etc for files in the source folder. When you see any event that may signal a move, check the "fingerprint" against the new file.

冰魂雪魄 2024-08-09 05:29:55

正如您已经提到的,使用 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 上跟踪文件系统事件的信息。

As you already mentioned, there is no reliable way to do this with the default FileSystemWatcher class provided by C#. You can apply certain heuristics like filename, hashes, or unique file ids to map created and deleted events together, but none of these approaches will work reliably. In addition, you cannot easily get the hash or file id for the file associated with the deleted event, meaning that you have to maintain these values in some sort of database.

I think the only reliable approach for detecting file movements is to create an own file system watcher. Therefore, you can use different approaches. If you are only going to watch changes on NTFS file systems, one solution might be to read out the NTFS change journal as described here. What's nice about this is that it even allows you to track changes that occurred while your app wasn't running.

Another approach is to create a minifilter driver that tracks file system operations and forwards them to your application. Using this you basically get all information about what is happening to your files and you'll be able to get information about moved files. A drawback of this approach is that you have to create a separate driver that needs to be installed on the target system. The good thing however is that you wouldn't need to start from scratch, because I already started to create something like this: https://github.com/CenterDevice/MiniFSWatcher

This allows you to simply track moved files like this:

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\\*");

However, please be aware that this requires kernel code that needs to be signed in order run on 64bit version of Windows (if you don't disable signature checking for testing). At time of writing, this code is also still in an early stage of development, so I would not use it on production systems yet. But even if you're not going to use this, it should still give you some information about how file system events might be tracked on Windows.

憧憬巴黎街头的黎明 2024-08-09 05:29:55

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

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

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

它还提到了有关移动文件的信息:

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

As far as I understand it, the Renamed event is for files being moved...?

My mistake - the docs specifically say that only files inside a moved folder are considered "renamed" in a cut-and-paste operation:

The operating system and FileSystemWatcher object interpret a cut-and-paste action or a move action as a rename action for a folder and its contents. If you cut and paste a folder with files into a folder being watched, the FileSystemWatcher object reports only the folder as new, but not its contents because they are essentially only renamed.

It also says about moving files:

Common file system operations might raise more than one event. For example, when a file is moved from one directory to another, several OnChanged and some OnCreated and OnDeleted events might be raised. Moving a file is a complex operation that consists of multiple simple operations, therefore raising multiple events.

瀞厅☆埖开 2024-08-09 05:29:55

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

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

I'll hazard a guess 'move' indeed does not exist, so you're really just going to have to look for a 'delete' and then mark that file as one that could be 'possibly moved', and then if you see a 'create' for it shortly after, I suppose you can assume you're correct.

Do you have a case of random file creations affecting your detection of moves?

哽咽笑 2024-08-09 05:29:55

Might want to try the OnChanged and/or OnRenamed events mentioned in the documentation.

手心的温暖 2024-08-09 05:29:55

StorageLibrary 类可以跟踪移动。来自 Microsoft 的示例:

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

可以在 此处找到完整示例
但是,您似乎只能跟踪 Windows 内部的更改“已知库”。

您还可以尝试使用 StorageFolder.TryGetChangeTracker()。但您的文件夹必须位于同步根目录下,您不能使用此方法获取文件系统中的任意文件夹。

StorageLibrary class can track moves. The example from Microsoft:

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

A complete example could be found here.
However, it looks like you can only track changes inside Windows "known libraries".

You can also try to get StorageLibraryChangeTracker using StorageFolder.TryGetChangeTracker(). But your folder must be under sync root, you can not use this method to get an arbitrary folder in file system.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文