C # - предсказывать события файловой системы при удалении папки - PullRequest
5 голосов
/ 11 февраля 2011

Это больше вопрос о том, как лучше всего это реализовать.

У меня есть FileSystemWatcher, который должен информировать меня об изменениях пользователя в файлах и папках. Также просматриваются subdirs. В той же директории моя программа тоже иногда меняется. Я не хочу, чтобы FileSystemWatcher обнаруживал события в этих изменениях программы.

Моей первой реализацией был список, в который я могу добавить ожидаемые события. Когда я получаю событие файловой системы, я проверяю список и игнорирую его, если оно есть. Это звучит не очень надежно, но, похоже, работает.

Теперь я обнаружил реальную проблему:
D: смотрит FileSystemWatcher.
У меня есть две такие папки: D: \ folder1 \ folder2
Теперь я хочу удалить folder1 (с папкой в ​​нем) с моим приложением. Поэтому я поместил D: \ folder1 в мой список удаления. Тогда я называю что-то вроде Directory.Delete(@"D:\folder1", true). Теперь я заметил, что folder1 не может быть удален (почему-либо) из-за исключения. Я удаляю запись об удалении из своего списка, но folder2 уже был удален, и я получаю его FileSystemEvent. Итак, я получаю событие FileSystem для D: \ folder1 \ folder2. Моя программа считает, что пользователь удалил эту папку и делает неправильные действия.

Теперь у меня было несколько идей:

1.) Рекурсивно удалить папку, удалив каждый файл и каждую папку отдельно. При этом я получаю для каждой подпапки и подаю собственную запись списка. Я уже реализовал это, но это очень очень очень медленно.

2.) Может быть, есть лучший способ использовать умные фильтры в FileSystemWatcher, чтобы сделать мой список устаревшим?

3.) Может быть, возможно удалить только дерево каталогов, если возможно удалить все. Так что, если это не удается, у меня все еще есть, а если не все удаляется. Мне кажется, это самое элегантное решение, но не знаю, возможно ли это вообще?

4.) Можно ли заблокировать все файлы и папки исключительно моим программным обеспечением? Если все прошло нормально, можно удалить все одной командой delete или как-то так?

Я также открыт для других дополнительных решений.

Отредактируйте 1, чтобы сделать его более понятным:

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

В моей реализации я получаю события для подпапок, если папка заблокирована и не может быть удалена.

Это не так просто объяснить на английском, потому что я не являюсь носителем английского языка;).

Редактировать 2:

5.) Может быть, можно FileSystemWatcher отфильтровать все события из определенного процесса?

Ответы [ 3 ]

2 голосов
/ 11 февраля 2011

Я недавно сделал именно такие вещи; хитрость заключается в том, чтобы ваш «список» распознавал, что там, где в списке есть имя папки, также отбрасывает любые события для чего-либо в этой папке, если она ожидает событие удаления, и удаляет его только из списка прогнозирования, если это сама папка.

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

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

РЕДАКТИРОВАТЬ: Также очень важно: события, которые возвращаются, делают это в другом потоке (если ваш обработчик не находится на объекте, который реализует ISynchronizeInvoke, например Control или Form, и вы устанавливаете SynchronizingObject на ваш Control / Form. Это означает, что вы должны быть очень осторожны с тем, как вы ведете свой список, с учетом возможных условий гонки. Я все еще борюсь с этим, мой код сбрасывает список прогнозов при получении событие ошибки, но к тому времени, когда оно обрабатывает событие, другие события изменения, так как ошибка уже была запущена и обработана, сбрасывает то, что не должно.

1 голос
/ 11 февраля 2011

По поводу переполнения буфера. Лучший способ решить эту проблему - выполнить работу в ответ на событие в другом потоке. Я делаю это так

// Queue of changed paths.
private readonly Queue<string> mEventQueue = new Queue<string>();

// add this as handler for filesystemwatcher events
public void FileSystemEvent(object source, FileSystemEventArgs e) {
    lock (mEventQueue) {
        if (!mEventQueue.Contains(e.FullPath)) {
            mEventQueue.Enqueue(e.FullPath);
            Monitor.Pulse(mEventQueue);
        }
    }
}

// start this on another thread
public void WatchLoop() {
    string path;
    while (true) {
        lock (mEventQueue) {
            while (mEventQueue.Count == 0)
                Monitor.Wait(mEventQueue);
            path = mEventQueue.Dequeue();
            if (path == null)
               break;
        }
        // do whatever you want to do
     }
}

Таким образом, я никогда не пропущу событие

0 голосов
/ 16 февраля 2011

Хорошо, вот мое решение проблемы:

Только для команды удаления:

Я реализовал 2 списка, один для удаления файла и один для удаления папки.

Записи в списке файлов не имеют времени ожидания.Если я удаляю файл, я создаю запись списка, и если я получаю ожидаемое событие удаления, я удаляю запись, как и раньше. У

записей списка папок нет времени ожидания после создания.Я могу подать команду вручную, чтобы через тайм-аут специальным методом.Если я удаляю папку, я добавляю запись в список deleteFolder.Каждое событие удаления из этой папки, файла, подпапки или подпапки игнорируется из-за этой записи об удалении папки.После того, как удаление завершено, я устанавливаю таймаут для записи deleteFolder.Если удаление вызывает исключение, я делаю то же самое.Поэтому я ожидаю получить все события через секунду.Поэтому я игнорирую все события, если команда удаления работает или нет.После этого запись списка deleteFolder будет удалена.

Ограничения: 1. все события удаления должны произойти через одну секунду после того, как удаление произошло.2. не разрешается удалять папку, как это:удалить папку (выполнено)создать папку сноваподождите менее 1 секундыснова удалить папку (время ожидания записи списка удаленных папок еще не истекло)

Надеюсь, это кому-нибудь поможет, даже если это очень сложно ^^

...