我意识到 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.
发布评论
评论(6)
根据 文档:
因此,如果您尝试非常小心地检测移动,并且具有相同的路径还不够好,那么您将不得不使用某种启发式方法。例如,使用源文件夹中的文件的文件名、大小、上次修改时间等创建“指纹”。当您看到任何可能表明移动的事件时,请根据新文件检查“指纹”。
According to the docs:
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.
正如您已经提到的,使用 C# 提供的默认 FileSystemWatcher 类没有可靠的方法来执行此操作。您可以应用某些启发式方法,例如文件名、哈希值或唯一文件 ID 来映射创建的和一起删除事件,但这些方法都无法可靠地工作。此外,您无法轻松获取与已删除事件关联的文件的哈希值或文件 ID,这意味着您必须在某种数据库中维护这些值。
我认为检测文件移动的唯一可靠方法是创建自己的文件系统观察器。因此,您可以使用不同的方法。如果您只想查看 NTFS 文件系统上的更改,一种解决方案可能是读出 NTFS 更改日志,如下所述 这里。这样做的好处是,它甚至允许您跟踪应用程序未运行时发生的更改。
另一种方法是创建一个微过滤器驱动程序来跟踪文件系统操作并将其转发到您的应用程序。使用此功能,您基本上可以获得有关文件发生情况的所有信息,并且您将能够获得有关移动文件的信息。这种方法的一个缺点是您必须创建一个需要安装在目标系统上的单独驱动程序。然而,好处是您不需要从头开始,因为我已经开始创建类似的东西: https ://github.com/CenterDevice/MiniFSWatcher
这允许您简单地跟踪移动的文件,如下所示:
但是,请注意,这需要需要签名的内核代码才能在 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:
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.
据我了解,
Renamed
事件用于移动文件......?我的错误 - 文档特别指出,在剪切和粘贴操作中,只有移动文件夹内的文件才被视为“重命名”:
它还提到了有关移动文件的信息:
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:
It also says about moving files:
我敢猜测“移动”确实不存在,所以你真的只需要查找“删除”,然后将该文件标记为可以“可能移动”的文件,然后如果你看到不久之后为其“创建”,我想您可以假设您是正确的。
您是否遇到过随机文件创建影响移动检测的情况?
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?
可能想尝试 中提到的 OnChanged 和/或 OnRenamed 事件文档。
Might want to try the OnChanged and/or OnRenamed events mentioned in the documentation.
StorageLibrary 类可以跟踪移动。来自 Microsoft 的示例:
可以在 此处找到完整示例。
但是,您似乎只能跟踪 Windows 内部的更改“已知库”。
您还可以尝试使用 StorageFolder.TryGetChangeTracker()。但您的文件夹必须位于同步根目录下,您不能使用此方法获取文件系统中的任意文件夹。
StorageLibrary class can track moves. The example from Microsoft:
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.