У меня есть приложение, в котором я ищу текстовый файл, и если какие-либо изменения были внесены в файл, я использую OnChanged
обработчик событий для обработки события. Я использую, NotifyFilters.LastWriteTime
но все равно событие запускается дважды. Вот код
public void Initialize()
{
FileSystemWatcher _fileWatcher = new FileSystemWatcher();
_fileWatcher.Path = "C:\\Folder";
_fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
_fileWatcher.Filter = "Version.txt";
_fileWatcher.Changed += new FileSystemEventHandler(OnChanged);
_fileWatcher.EnableRaisingEvents = true;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
.......
}
В моем случае OnChanged
вызывается дважды, когда я изменить текстовый файл version.txt
и сохранить его.
c#
filesystemwatcher
user214707
источник
источник
Ответы:
Я боюсь, что это хорошо известная ошибка / особенность
FileSystemWatcher
класса. Это из документации класса:Теперь этот фрагмент текста о
Created
событии, но то же самое относится и к другим событиям файла. В некоторых приложениях вы можете обойти это, используяNotifyFilter
свойство, но мой опыт говорит, что иногда вам также необходимо выполнить некоторую ручную фильтрацию дубликатов (хаки).Некоторое время назад я отметил страницу с несколькими советами FileSystemWatcher . Вы можете проверить это.
источник
Я «исправил» эту проблему, используя следующую стратегию в моем делегате:
источник
Любые дублированные
OnChanged
события изFileSystemWatcher
могут быть обнаружены и отброшены путем проверкиFile.GetLastWriteTime
метки времени в рассматриваемом файле. Вот так:источник
"Rename"
название интересующего вас события):Observable.FromEventPattern<FileSystemEventArgs>(fileSystemWatcher, "Renamed") .Select(e => e.EventArgs) .Distinct(e => e.FullPath) .Subscribe(onNext);
DateTime
только имеет разрешение в миллисекундах, этот метод работает, даже если вы заменитеFile.GetLastWriteTime
наDateTime.Now
. В зависимости от вашей ситуации вы также можете использоватьa.FullName
глобальную переменную in для обнаружения повторяющихся событий.Вот мое решение, которое помогло мне остановить событие дважды:
Здесь я установил
NotifyFilter
свойство только с именем файла и размером.watcher
мой объект FileSystemWatcher Надеюсь, это поможет.источник
Мой сценарий состоит в том, что у меня есть виртуальная машина с сервером Linux. Я занимаюсь разработкой файлов на хосте Windows. Когда я изменяю что-то в папке на хосте, я хочу, чтобы все изменения были загружены, синхронизированы с виртуальным сервером через Ftp. Вот как я устраняю событие изменения дубликата при записи в файл (который также помечает папку, содержащую файл, который нужно изменить):
В основном я создаю хеш-таблицу для хранения информации о времени записи файла. Затем, если в хеш-таблице есть измененный путь к файлу, и его значение времени совпадает с уведомлением об изменении файла в настоящий момент, то я знаю, что это дубликат события, и игнорирую его.
источник
ToString("o")
но будьте готовы к большему количеству ошибокПопробуйте с этим кодом:
источник
if (let==false) { ... } else { let = false; }
? Невероятно, как это получило голоса, это должно быть только из значков StackOverflow.Вот мой подход:
Это решение, которое я использовал для решения этой проблемы в проекте, где я отправлял файл в виде вложения по почте. Он легко избежит дважды запущенного события даже с меньшим интервалом таймера, но в моем случае с 1000 все было в порядке, поскольку я был счастлив, пропустив несколько изменений, чем при заполнении почтового ящика с> 1 сообщением в секунду. По крайней мере, это работает просто отлично, если несколько файлов изменяются одновременно.
Другое решение, о котором я подумал, - это заменить список файлами сопоставления словаря на соответствующие MD5, чтобы вам не пришлось выбирать произвольный интервал, поскольку вам не нужно удалять запись, а обновлять ее значение, и отмени свой материал, если он не изменился. Недостатком является увеличение словаря в памяти, поскольку файлы отслеживаются и потребляют все больше и больше памяти, но я где-то читал, что количество отслеживаемых файлов зависит от внутреннего буфера FSW, так что, возможно, это не так критично. Не знаю, как время работы MD5 повлияет на производительность вашего кода, осторожно = \
источник
lock (_changedFiles) { if (_changedFiles.Contains(e.FullPath)) { return; } _changedFiles.Add(e.FullPath); // add this! } // do your stuff
_changedFiles
Доступ из нескольких потоков. Один из способов исправить это - использоватьConcurrentDictionary
вместоList
. Другой способ заключается в назначении токаForm
наTimer.SynchronizingObject
имущество, а также вFileSystemWatcher.SynchronizingObject
собственности.Я создал репозиторий Git с классом, который расширяет
FileSystemWatcher
возможности запуска событий только после завершения копирования. Он отменяет все измененные события, кроме последнего, и вызывает его только тогда, когда файл становится доступным для чтения.Загрузите FileSystemSafeWatcher и добавьте его в свой проект.
Затем используйте его как нормальный
FileSystemWatcher
и наблюдайте, когда события вызваны.источник
Я знаю, что это старая проблема, но у нее была та же проблема, и ни одно из приведенных выше решений не помогло решить проблему, с которой я столкнулся. Я создал словарь, который сопоставляет имя файла с LastWriteTime. Таким образом, если файл отсутствует в словаре, будет продолжен процесс другой мудрой проверки, чтобы увидеть, когда было последнее измененное время и если оно отличается от того, что в словаре, запустите код.
источник
your code here
разделе вы должны добавить или обновить dateTimeDictionary.dateTimeDictionary[e.FullPath] = System.IO.File.GetLastWriteTime(e.FullPath);
Одним из возможных «взломов» может быть регулирование событий с помощью Reactive Extensions, например:
В этом случае я сокращаю до 50 мс, в моей системе этого было достаточно, но более высокие значения должны быть безопаснее. (И, как я уже сказал, это все еще «взлом»).
источник
.Distinct(e => e.FullPath)
что я считаю более интуитивным, чтобы иметь дело с. И вы восстановили поведение, которое можно ожидать от API.У меня есть очень быстрый и простой обходной путь, он работает для меня, и независимо от того, будет ли событие запускаться один или два или более раз изредка, проверьте его:
источник
Вот новое решение, которое вы можете попробовать. Хорошо работает для меня. В обработчике события для измененного события программно удалите обработчик из конструктора, при необходимости выведите сообщение, затем программно добавьте обработчик обратно. пример:
источник
this.fileSystemWatcher1.Changed -= this.fileSystemWatcher1_Changed;
должен делать правильные вещи.Основной причиной было то, что время последнего обращения к первому событию было текущее время (время записи или изменения файла). затем второе событие было исходным временем последнего доступа к файлу. Я решаю по коду.
источник
Я провел довольно много времени, используя FileSystemWatcher, и некоторые из подходов здесь не будут работать. Мне очень понравился подход отключения событий, но, к сожалению, он не работает, если есть> 1 файл, который будет пропущен, второй файл будет пропущен больше всего, если не все время. Поэтому я использую следующий подход:
источник
Этот код работал для меня.
источник
в основном на будущее мне :)
Я написал обертку, используя Rx:
Использование:
источник
Я изменил способ контроля файлов в каталогах. Вместо использования FileSystemWatcher я опрашиваю местоположения в другом потоке, а затем просматриваю LastWriteTime файла.
Используя эту информацию и ведя индекс пути к файлу и времени его последней записи, я могу определить файлы, которые были изменены или были созданы в определенном месте. Это удаляет меня от странностей FileSystemWatcher. Основным недостатком является то, что вам нужна структура данных для хранения LastWriteTime и ссылки на файл, но она надежна и проста в реализации.
источник
Вы можете попытаться открыть его для записи, и в случае успеха вы можете предположить, что другое приложение завершило работу с файлом.
Просто открытие его для записи не вызывает изменения события. Так что это должно быть безопасно.
источник
источник
Извините за могилу, но я боролся с этой проблемой некоторое время и наконец нашел способ справиться с этими многочисленными событиями. Я хотел бы поблагодарить всех в этой теме, поскольку я использовал это во многих ссылках, когда боролся с этой проблемой.
Вот мой полный код. Он использует словарь для отслеживания даты и времени последней записи файла. Он сравнивает это значение и, если он совпадает, подавляет события. Затем он устанавливает значение после запуска нового потока.
источник
Событие, если не спросили, жаль, что нет готовых образцов решения для F #. Чтобы исправить это, вот мой рецепт, потому что я могу, и F # - замечательный язык .NET.
Дублированные события отфильтровываются с использованием
FSharp.Control.Reactive
пакета, который является просто оболочкой F # для реактивных расширений. Все, что может быть нацелено на полную структуру илиnetstandard2.0
:источник
В моем случае необходимо получить последнюю строку текстового файла, который вставляется другим приложением, как только вставка будет завершена. Вот мое решение. Когда возникает первое событие, я отключаю наблюдателя от вызова других, затем вызываю таймер TimeElapsedEvent, потому что когда вызывается моя функция-обработчик OnChanged, мне нужен размер текстового файла, но размер в это время не является действительным размером, это размер файла сразу перед вставкой. Так что я жду некоторое время, чтобы продолжить с правильным размером файла.
источник
Попробуйте это, это работает нормально
источник
Я хотел отреагировать только на последнее событие, на всякий случай, также на изменение файла linux, казалось, что файл был пустым при первом вызове, а затем снова заполнен при следующем и не возражал потерять некоторое время на всякий случай ОС решил сделать некоторые изменения файла / атрибута.
Я использую асинхронную .NET здесь, чтобы помочь мне сделать поток.
источник
Я думаю, что лучшим решением для решения этой проблемы является использование реактивных расширений. Когда вы преобразуете событие в наблюдаемое, тогда вы можете просто добавить Throttling (..) (первоначально он назывался Debounce (..)).
Пример кода здесь
источник
Я смог сделать это, добавив функцию, которая проверяет наличие дубликатов в массиве буферов.
Затем выполните действие после того, как массив не был изменен в течение X времени, используя таймер: - Сбрасывать таймер каждый раз, когда что-то записывается в буфер - Выполнять действие по тику
Это также ловит другой тип дублирования. Если вы изменяете файл внутри папки, папка также генерирует событие Change.
источник
Это решение работало для меня в производственном приложении:
Окружающая среда:
VB.Net Framework 4.5.2
Установите свойства объекта вручную: NotifyFilter = Size
Затем используйте этот код:
источник
Попробуй это!
источник
Мне пришлось объединить несколько идей из постов выше и добавить проверку блокировки файлов, чтобы она работала на меня:
источник
Я подошел к проблеме двойного создания, которая игнорирует первое событие:
источник