Событие FileSystemWatcher Changed генерируется дважды

YEAR() - это функция mysql , вы должны использовать whereRaw() для запроса этого. Например:

->whereRaw('YEAR(docdate) = 2019')

Обновление:

Для вашей части whereIn() вы должны сделать два запроса, по одному для каждого столбца. Таким образом, вам нужно будет получить правильные значения из массива. Это можно сделать с помощью array_map.

Например:

->whereIn('comp', array_map(function($cat) { return $cat['comp']; }, $categories))
->whereIn('cus', array_map(function($cat) { return $cat['cus']; }, $categories))

317
задан SteveC 15 June 2012 в 04:13
поделиться

10 ответов

Боюсь, что это хорошо известная ошибка / особенность класса FileSystemWatcher . Это из документации класса:

В определенных ситуациях вы можете заметить, что одно событие создания генерирует несколько событий Created, которые обрабатываются вашим компонентом. Например, если вы используете компонент FileSystemWatcher для отслеживания создания новых файлов в каталоге, а затем тестируете его с помощью Блокнота для создания файла, вы можете увидеть два события Created, сгенерированных, даже если был создан только один файл. Это связано с тем, что в процессе записи Блокнот выполняет несколько действий с файловой системой. Блокнот записывает на диск пакетами, которые создают содержимое файла, а затем атрибуты файла. Другие приложения могут работать таким же образом. Поскольку FileSystemWatcher отслеживает действия операционной системы, все события, запускаемые этими приложениями, будут захвачены.

Теперь этот фрагмент текста относится к событию Created , но то же самое относится и к другим файловым событиям. . В некоторых приложениях вы можете обойти это, используя свойство NotifyFilter , но мой опыт показывает, что иногда вам также нужно выполнить некоторую ручную дублирующую фильтрацию (хаки).

Некоторое время назад Я добавил в закладки страницу с несколькими советами FileSystemWatcher . Вы можете проверить это.

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

Некоторое время назад Я добавил в закладки страницу с несколькими советами FileSystemWatcher . Вы можете проверить это.

В некоторых приложениях вы можете обойти это, используя свойство NotifyFilter , но мой опыт показывает, что иногда вам также нужно выполнить некоторую ручную дублирующую фильтрацию (хаки).

Некоторое время назад Я добавил в закладки страницу с несколькими советами FileSystemWatcher . Вы можете проверить это.

270
ответ дан 23 November 2019 в 01:02
поделиться

Я изменил способ отслеживания файлов в каталогах. Вместо использования FileSystemWatcher я опрашиваю местоположения в другом потоке, а затем смотрю на LastWriteTime файла.

DateTime lastWriteTime = File.GetLastWriteTime(someFilePath);

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

1
ответ дан 23 November 2019 в 01:02
поделиться

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

private void OnChanged(object source, FileSystemEventArgs e)
{
    try
    {
        using (var fs = File.OpenWrite(e.FullPath))
        {
        }
        //do your stuff
    }
    catch (Exception)
    {
        //no write access, other app not done
    }
}

Кажется, что простое открытие его для записи не вызывает измененное событие. Так что это должно быть безопасно.

1
ответ дан 23 November 2019 в 01:02
поделиться

Я "исправил" эту проблему, используя следующую стратегию в моем делегате:

// fsw_ is the FileSystemWatcher instance used by my application.

private void OnDirectoryChanged(...)
{
   try
   {
      fsw_.EnableRaisingEvents = false;

      /* do my stuff once asynchronously */
   }

   finally
   {
      fsw_.EnableRaisingEvents = true;
   }
}
145
ответ дан 23 November 2019 в 01:02
поделиться

Любые дублирующиеся OnChanged события от FileSystemWatcher можно обнаружить и отбросить, проверив File.GetLastWriteTime временную метку для данного файла. Например:

DateTime lastRead = DateTime.MinValue;

void OnChanged(object source, FileSystemEventArgs a)
{
    DateTime lastWriteTime = File.GetLastWriteTime(uri);
    if (lastWriteTime != lastRead)
    {
        doStuff();
        lastRead = lastWriteTime;
    }
    // else discard the (duplicated) OnChanged event
}
103
ответ дан 23 November 2019 в 01:02
поделиться

Мой сценарий таков: у меня есть виртуальная машина с сервером Linux на ней. Я разрабатываю файлы на хосте Windows. Когда я изменяю что-то в папке на хосте, я хочу, чтобы все изменения загружались, синхронизировались на виртуальный сервер через Ftp. Вот как я устраняю дублирующее событие изменения при записи в файл (что отмечает папку, содержащую файл, как измененную) :

private Hashtable fileWriteTime = new Hashtable();

private void fsw_sync_Changed(object source, FileSystemEventArgs e)
{
    string path = e.FullPath.ToString();
    string currentLastWriteTime = File.GetLastWriteTime( e.FullPath ).ToString();

    // if there is no path info stored yet
    // or stored path has different time of write then the one now is inspected
    if ( !fileWriteTime.ContainsKey(path) ||
         fileWriteTime[path].ToString() != currentLastWriteTime
    )
    {
        //then we do the main thing
        log( "A CHANGE has occured with " + path );

        //lastly we update the last write time in the hashtable
        fileWriteTime[path] = currentLastWriteTime;
    }
}

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

7
ответ дан 23 November 2019 в 01:02
поделиться

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

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

public static class FileSystemWatcherExtensions
{
    public static IDisposable OnAnyEvent(this FileSystemWatcher source,
        WatcherChangeTypes changeTypes, FileSystemEventHandler handler, int delay)
    {
        var cancellations = new Dictionary<string, CancellationTokenSource>(
            StringComparer.OrdinalIgnoreCase);
        var locker = new object();
        if (changeTypes.HasFlag(WatcherChangeTypes.Created))
            source.Created += FileSystemWatcher_Event;
        if (changeTypes.HasFlag(WatcherChangeTypes.Deleted))
            source.Deleted += FileSystemWatcher_Event;
        if (changeTypes.HasFlag(WatcherChangeTypes.Changed))
            source.Changed += FileSystemWatcher_Event;
        if (changeTypes.HasFlag(WatcherChangeTypes.Renamed))
            source.Renamed += FileSystemWatcher_Event;
        return new Disposable(() =>
        {
            source.Created -= FileSystemWatcher_Event;
            source.Deleted -= FileSystemWatcher_Event;
            source.Changed -= FileSystemWatcher_Event;
            source.Renamed -= FileSystemWatcher_Event;
        });

        async void FileSystemWatcher_Event(object sender, FileSystemEventArgs e)
        {
            var key = e.FullPath;
            var cts = new CancellationTokenSource();
            lock (locker)
            {
                if (cancellations.TryGetValue(key, out var existing))
                {
                    existing.Cancel();
                }
                cancellations[key] = cts;
            }
            try
            {
                await Task.Delay(delay, cts.Token);
                // Omitting ConfigureAwait(false) is intentional here.
                // Continuing in the captured context is desirable.
            }
            catch (TaskCanceledException)
            {
                return;
            }
            lock (locker)
            {
                if (cancellations.TryGetValue(key, out var existing)
                    && existing == cts)
                {
                    cancellations.Remove(key);
                }
            }
            cts.Dispose();
            handler(sender, e);
        }
    }

    public static IDisposable OnAllEvents(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.All, handler, delay);

    public static IDisposable OnCreated(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.Created, handler, delay);

    public static IDisposable OnDeleted(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.Deleted, handler, delay);

    public static IDisposable OnChanged(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.Changed, handler, delay);

    public static IDisposable OnRenamed(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.Renamed, handler, delay);

    private struct Disposable : IDisposable
    {
        private readonly Action _action;
        internal Disposable(Action action) => _action = action;
        public void Dispose() => _action?.Invoke();
    }
}

пример Использования:

myWatcher.OnAnyEvent(WatcherChangeTypes.Created | WatcherChangeTypes.Changed,
    MyFileSystemWatcher_Event, 100);

Эта строка комбинирует подписку к двум событиям, Created и Changed. Таким образом, это примерно эквивалентно им:

myWatcher.Created += MyFileSystemWatcher_Event;
myWatcher.Changed += MyFileSystemWatcher_Event;

различие - то, что эти два события рассматриваются как единственный тип события, и в случае быстрой последовательности этих событий только будет распространено последнее. Например, если Created событие будет сопровождаться два Changed события, и нет никакого разрыва времени, больше, чем 100 мс между этими тремя событиями, только второе Changed, то событие будет распространено путем вызова MyFileSystemWatcher_Event обработчик, и предыдущие будут отброшены.

0
ответ дан 23 November 2019 в 01:02
поделиться

Я думаю, что лучшее решение решить проблему состоит в том, чтобы использовать реактивные расширения при преобразовании события в заметный затем можно просто добавить Регулировку (..) (первоначально названный Debounce (..))

Пример кода здесь

        var templatesWatcher = new FileSystemWatcher(settingsSnapshot.Value.TemplatesDirectory)
        {
            NotifyFilter = NotifyFilters.LastWrite,
            IncludeSubdirectories = true
        };

        templatesWatcher.EnableRaisingEvents = true;

        Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
                addHandler => templatesWatcher.Changed += addHandler,
                removeHandler => templatesWatcher.Changed -= removeHandler)
            .Throttle(TimeSpan.FromSeconds(5))
            .Subscribe(args =>
            {
                _logger.LogInformation($"Template file {args.EventArgs.Name} has changed");
                //TODO do something
            });
0
ответ дан 23 November 2019 в 01:02
поделиться

Поиск отвечает, но я предложил грязное решение. Так как мое событие стреляет дважды, второе действие ничего не делает.

       $count = 1
       $action = { 
            if($count -eq 1){                  
                #DO SOMETHING
                $count = 2 
            }else{
                $count = 1
            }
        }  
-1
ответ дан 23 November 2019 в 01:02
поделиться

если вы регистрируетесь на событие OnChanged, то удаление контролируемого файла перед его изменением может сработать, пока вам нужно отслеживать только событие OnChange. .

-2
ответ дан 23 November 2019 в 01:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: