Обнаружение перемещенных файлов с помощью FileSystemWatcher

Я понимаю, что FileSystemWatcher не предоставляет событие Move, вместо этого он будет генерировать отдельные события Delete и Create для того же файла. (FilesystemWatcher просматривает как исходную, так и целевую папки).

Однако как мы можем различать истинный перемещение файла и случайное создание файла, имеющего то же имя, что и недавно удаленный файл?

Некоторое свойство класса FileSystemEventArgs, такое как "AssociatedDeleteFile", которому назначен удаленный путь к файлу, если он является результатом перемещения, или NULL в противном случае будет отличным. Но, конечно, этого не существует.

Я также понимаю, что FileSystemWatcher работает на базовом уровне файловой системы, поэтому концепция "Move" может иметь смысл только для приложений более высокого уровня. Но если это так, то какой алгоритм люди рекомендуют обрабатывать эту ситуацию в моем приложении?

Обновление на основе обратной связи:

Класс FileSystemWatcher, похоже, отображает перемещение файла как просто 2 различных события, удаление исходного файла, а затем Создать в новом месте.

К сожалению, между этими событиями нет "ссылки", поэтому неясно, как различать перемещение файла и нормальное удаление или создание. На уровне ОС движение обрабатывается специально, вы можете перемещаться, скажем, 1 ГБ файл почти мгновенно.

Несколько ответов предложили использовать хэш на файлах, чтобы надежно идентифицировать их между событиями, и я буду использовать этот подход. Но если кто-то знает, как проще определить движение, пожалуйста, оставьте ответ.

Ответы

Ответ 1

В соответствии с docs:

Общие действия файловой системы могут вызывают более одного события. Для Например, когда файл перемещается из одного каталог другому, несколько OnChanged и некоторые OnCreated и События OnDeleted могут быть подняты. Перемещение файла - сложная операция который состоит из нескольких простых операций, поэтому повышение количества события.

Итак, если вы пытаетесь быть очень осторожными в обнаружении ходов, а одно и то же имя недостаточно, вам придется использовать какую-то эвристику. Например, создайте "отпечаток пальца", используя имя файла, размер, последнее измененное время и т.д. Для файлов в исходной папке. Когда вы видите какое-либо событие, которое может сигнализировать о движении, проверьте "отпечаток пальца" на новый файл.

Ответ 2

Насколько я понимаю, событие Renamed предназначено для перемещения файлов...?

Моя ошибка - в документах указано, что только файлы внутри перемещенной папки считаются "переименованными" в операции "вырезать и вставлять":

Операционная система и объект FileSystemWatcher интерпретируют действие вырезания и вставки или действие перемещения как действие переименования для папки и ее содержимого. Если вы вырезаете и вставляете папку с файлами в просматриваемую папку, объект FileSystemWatcher сообщает только о папке как о новой, но не о ее содержимом, потому что они по существу только переименованы.

В нем также говорится о перемещении файлов:

Общие действия файловой системы могут приводить к нескольким событиям. Например, когда файл перемещается из одного каталога в другой, могут быть подняты несколько событий OnChanged и некоторых OnCreated и OnDeleted. Перемещение файла представляет собой сложную операцию, состоящую из нескольких простых операций, поэтому возникает несколько событий.

Ответ 3

Я буду опасаться, что "move" действительно не существует, поэтому вам действительно нужно искать "удалить", а затем пометить этот файл как "который может быть" перемещен ", а затем если вы вскоре увидите" создать", я полагаю, вы можете предположить, что вы правы.

Есть ли у вас случай случайных созданий файлов, влияющих на ваше обнаружение ходов?

Ответ 4

Возможно, вы захотите попробовать события OnChanged и/или OnRenamed, упомянутые в документации.

Ответ 5

Как вы уже упоминали, нет надежного способа сделать это с помощью стандартного класса FileSystemWatcher, предоставляемого С#. Вы можете применить определенные эвристики, такие как имя файла, хеши или уникальные идентификаторы файлов, чтобы сопоставить созданные и удаленные события вместе, но ни один из этих подходов не будет работать надежно. Кроме того, вы не можете легко получить хэш или идентификатор файла для файла, связанного с удаленным событием, что означает, что вы должны поддерживать эти значения в какой-то базе данных.

Я думаю, что единственным надежным подходом для обнаружения движений файлов является создание собственного наблюдателя файловой системы. Поэтому вы можете использовать разные подходы. Если вы собираетесь просматривать изменения в файловых системах 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 (если вы не disable проверка подписи для тестирования). На момент написания этого кода этот код также находится на ранней стадии разработки, поэтому я бы не использовал его на производственных системах. Но даже если вы не собираетесь использовать это, он все равно должен предоставить вам некоторую информацию о том, как отслеживать события файловой системы в Windows.