Detecting moved files using FileSystemWatcher

后端 未结 6 675
面向向阳花
面向向阳花 2020-11-30 06:54

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 wa

相关标签:
6条回答
  • 2020-11-30 07:05

    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?

    0 讨论(0)
  • 2020-11-30 07:07

    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.

    0 讨论(0)
  • 2020-11-30 07:19

    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.

    0 讨论(0)
  • 2020-11-30 07:30

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

    0 讨论(0)
  • 2020-11-30 07:31

    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.

    0 讨论(0)
  • 2020-11-30 07:31

    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.

    0 讨论(0)
提交回复
热议问题