#c_sharp #net
Мониторинг файла. При изменениях в файле почему-то дважды запускается Change. Как можно это решить? Вот код: public void monitoring(string path) { this.sPath = path; string first = Path.GetDirectoryName(path); string second = Path.GetFileName(path); FileSystemWatcher fsw = new FileSystemWatcher(first, second); fsw.Changed += new FileSystemEventHandler(watcher_Changed); fsw.EnableRaisingEvents = true; } public void watcher_Changed(object sender, FileSystemEventArgs e) { MessageBox.Show("Be happy :3"); SplitAndQuery(this.sPath); }
Ответы
Ответ 1
Дело в том, что FileSystemWatcher опирается на уведомления от ОС. А запись изменений в файл далеко не всегда может являться атомарным действием: например, notepad.exe пишет на диск в несколько приемов, отдельно файл и отдельно его атрибуты, что повлечет за собой несколько срабатываний события Changed. Или при копировании/перемещении файлов запись происходит в несколько приемов. Избавиться от этого можно попробовать разными способами. Самый железобетонный, но не всегда подходящий -- отключать генерацию событий. Но пользоваться им надо аккуратно, т.к. можно пропустить другие полезные изменения. public void watcher_Changed(object sender, FileSystemEventArgs e) { watcher.EnableRaisingEvents = false; try { MessageBox.Show("Be happy :3"); SplitAndQuery(this.sPath); } finally { watcher.EnableRaisingEvents = true; } } Другой подход -- опираться на дату последней модификации файла (опционально еще и на e.ChangeType): DateTime lastWriteTime = DateTime.MinValue; public void watcher_Changed(object sender, FileSystemEventArgs e) { DateTime writeTime = File.GetLastWriteTime(this.sPath); if (lastWriteTime != writeTime) { MessageBox.Show("Be happy :3"); SplitAndQuery(this.sPath); lastWriteTime = writeTime; } } Если файл изменяется не очень часто, а события приходят одно за другим, то можно использовать таймер с некоторым ожиданием и отсекать события, для которых не прошло нужное количество времени. В общем, выбор решения целиков зависит от ваших требований (впрочем, как обычно :)).Ответ 2
Никак, просто имейте в виду, что событие срабатывает дважды. Это нормально для FileSystemWatcher. Конкретные решения придётся принимать по ситуации. Я обычно держу в классах информацию, которая мне помогает понять, надо обрабатывать текущее событие changed или нет - последнее время изменения, текущее местоположение файла, наличие файла и т.д.Ответ 3
Решение со счетчиком опасно, т.к. игнорирует возможные другие изменения. Есть вариант с отложенным исполнением, когда пропускаются изменения только в момент ожидания. private FileSystemWatcher _watcher = new FileSystemWatcher(); public void Start() { .... _watcher.Changed += _watcher_Changed; _watcher.EnableRaisingEvents = true; } private void _watcher_Changed(object sender, FileSystemEventArgs e) { new Thread(ReloadData).Start(); // запускаем в отдельном потоке, для отсечения очереди событий при многоэтапной записи в файл } private void ReloadData() { // блокируем выполнение для пропуска нескольких этапов записи файла if (Monitor.TryEnter(_watcher)) { try { Thread.Sleep(3000); // ждём 3 сек пока файл сохраняется } finally { Monitor.Exit(_watcher); } } else { return; // все остальные входы в течении 3 секунд будут игнорироваться } // через 3 секунды происходит реакция Execute(); }Ответ 4
Нашел решение которое мне подходит, но не факт что подойдет всем: public void watcher_Changed(object sender, FileSystemEventArgs e) { changeCount++; if (changeCount == 1) { MessageBox.Show("Be happy :3"); SplitAndQuery(this.sPath); } else { changeCount = 0; MessageBox.Show("Be very happy, its works"); } }
Комментариев нет:
Отправить комментарий