VB.NET FileSystemWatcher несколько событий изменения

Поскольку с именами не связан идентификатор, я бы просто использовал ROW_NUMBER и присоединился к ROW_NUMBER = unique_reviser_code. Единственная проблема состоит в том, чтобы знать, какие строки являются нулевыми Из того, что я вижу, все они кажутся нулевыми. По вашим данным, так ли это, или в таблице периодически встречаются имена, например, 5, 17, 29 ... и т. Д.? Если name_expedient_reviser пуст в dbo_expedient_reviser, вы также можете усечь таблицу и напрямую вставить значения. Надеюсь, этот уникальный_ревизер-код уже не связан с другими вещами.

WITH CTE (name_expedient_reviser, unique_reviser_code)
AS
    (
    SELECT   name_expedient_reviser
            ,ROW_NUMBER() OVER (ORDER BY name_expedient_reviser)
    FROM source_table
    )
UPDATE er
SET er.name_expedient_reviser = cte.name_expedient_reviser      
FROM dbo_expedient_reviser er
JOIN CTE on cte.unique_reviser_code = er.unique_reviser_code

Или усечь:

Truncate Table dbo_expedient_reviser

INSERT INTO dbo_expedient_reviser (name_expedient_reviser, unique_reviser_code)
SELECT DISTINCT
    unique_reviser_code = ROW_NUMBER() OVER (ORDER BY name_expedient_reviser)
   ,name_expedient_reviser
FROM source_table
11
задан John Saunders 9 June 2010 в 02:07
поделиться

11 ответов

От раздела "Troubleshooting FileSystemWatcher Components" документации VS.NET...

Несколько созданных событий, сгенерированных для единственного действия

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

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

16
ответ дан 3 December 2019 в 01:13
поделиться

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


Править: У Вас есть какой-либо антивирус, автозащищают выполнение программного обеспечения? Они могли бы касаться файла в процессе.

Из документации MSDN:

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


Править: Или возможно существует что-то, чтобы сделать с тем, как окна сохранили файл. Вы могли бы получать больше чем одно событие от различных изменений. (Один для размера, один для последней метки времени записи, один для последней метки времени доступа и еще одного для... чего-то еще.) Установка Try FileSystemWatcher NotifyFilter свойство к единственному типу изменения и видит, продолжаете ли Вы получать несколько событий.

1
ответ дан 3 December 2019 в 01:13
поделиться

Существует другая возможность, которая Вы делаете ошибку :) Возможно, Вы, инстанцируют и завершают Ваш "Скучный" класс перед использованием его для filewatching цели, и упущение реализовать RemoveHandler Располагает/или любой связанный метод разрушения. (?)

1
ответ дан 3 December 2019 в 01:13
поделиться

Только что я имею, испытывают ту же проблему.

После некоторого поиска thtrough сеть, казалось, что я не был единственным, имеющим эту проблему.:) Так, возможно, это - дефект в FileSystemWatcher...

Я решил его путем отслеживания прошлый раз, когда eventhandler был повышен. Если это было повышено меньше затем xxx msec назад, я возвращаюсь из своего eventhandler. Если кто-либо знает фиксацию, которая более изящна; сообщите мне.:)

Это - то, как я работал вокруг этого:

if( e.ChangeType == WatcherChangeTypes.Changed )
{

    // There is a nasty bug in the FileSystemWatch which causes the 
    // events of the FileSystemWatcher to be called twice.
    // There are a lot of resources about this to be found on the Internet,
    // but there are no real solutions.
    // Therefore, this workaround is necessary: 
    // If the last time that the event has been raised is only a few msec away, 
    // we ignore it.
    if( DateTime.Now.Subtract (_lastTimeFileWatcherEventRaised).TotalMilliseconds < 500 )
    {
        return;
    }


    _lastTimeFileWatcherEventRaised = DateTime.Now;


    .. handle event
14
ответ дан 3 December 2019 в 01:13
поделиться

Я написал код, который решает эту проблему и другие полезные функции FileSystemWatcher. Он размещен в моем блоге по адресу: http://precisionsoftware.blogspot.com/2009/05/filesystemwatcher-done-right.html

1
ответ дан 3 December 2019 в 01:13
поделиться

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

Ура,

Нико

1
ответ дан 3 December 2019 в 01:13
поделиться

Вот доказательство концепции того, как я с этим справляюсь.

Для проверки создайте новое приложение Windows Forms. В форме добавьте многострочное текстовое поле с именем «tbMonitor». Щелкните форму правой кнопкой мыши и перейдите к Просмотр кода. Замените этот код приведенным ниже кодом. Обратите внимание, что я установил очень большое время ожидания, чтобы вы могли немного поиграть с ним. В производственной среде вы, вероятно, захотите сделать это число намного меньше, вероятно, около 10 или 15.

Imports System.IO
Imports System.Threading
Public Class Form1
Private Const MILLISECONDS_TO_WAIT As Integer = 1000
Private fw As FileSystemWatcher
Private Shared AccessEntries As List(Of String)
Private Delegate Sub UpdateBoxDelegate(ByVal msg As String)
Private Sub UpdateBox(ByVal msg As String)
    If tbMonitor.InvokeRequired Then
        Invoke(New UpdateBoxDelegate(AddressOf UpdateBox), New Object() {msg})
    Else
        tbMonitor.AppendText(msg + vbCrLf)
    End If
End Sub

Private Sub AccessEntryRemovalTimer(ByVal RawFileName As Object)
    UpdateBox("Sleeping to watch for " + RawFileName.ToString + " on thread ID " + Thread.CurrentThread.ManagedThreadId.ToString)
    Thread.Sleep(MILLISECONDS_TO_WAIT)
    AccessEntries.Remove(RawFileName.ToString)
    UpdateBox("Removed " + RawFileName.ToString + " in thread ID " + Thread.CurrentThread.ManagedThreadId.ToString)
End Sub

Private Sub Changed(ByVal source As Object, ByVal e As FileSystemEventArgs)
    If AccessEntries.Contains(e.Name) Then
        UpdateBox("Ignoring a " + e.ChangeType.ToString + " notification for " + e.Name + " in thread ID " + Thread.CurrentThread.ManagedThreadId.ToString)
        Return
    End If
    Dim AccessTimerThread As Thread

    AccessEntries.Add(e.Name)
    UpdateBox("Adding " + e.Name + " to the collection and starting the watch thread.")
    AccessTimerThread = New Thread(AddressOf AccessEntryRemovalTimer)
    AccessTimerThread.IsBackground = True
    AccessTimerThread.Start(e.Name)

End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    tbMonitor.ScrollBars = ScrollBars.Both
    AccessEntries = New List(Of String)
    fw = New FileSystemWatcher
    fw.Path = "C:\temp"
    fw.NotifyFilter = NotifyFilters.LastWrite Or NotifyFilters.LastAccess Or NotifyFilters.FileName
    AddHandler fw.Changed, AddressOf Changed
    AddHandler fw.Created, AddressOf Changed
    AddHandler fw.Renamed, AddressOf Changed
    fw.EnableRaisingEvents = True
End Sub

Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    fw.EnableRaisingEvents = False
    RemoveHandler fw.Changed, AddressOf Changed
    RemoveHandler fw.Created, AddressOf Changed
    RemoveHandler fw.Renamed, AddressOf Changed
    fw.Dispose()
End Sub
End Class
1
ответ дан 3 December 2019 в 01:13
поделиться

My solution to this problem is a bit like Erics except I use a System.Windows.Forms.Timer in stead of starting a new thread. The idea is that I handle the change event only when x ms have passed without any file changed events. Note that everything takes place on the GUI thread so there are no threading issues. I use x = 100.

    private Dictionary<String, FileSystemEventArgs> xmlFileChangedEvents = new Dictionary<string, FileSystemEventArgs>();
    private void debugXmlWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        if (!xmlFileChangedEvents.ContainsKey(e.Name))
            xmlFileChangedEvents.Add(e.Name, e);
        xmlChangeTimer.Stop();//Reset the Forms.Timer so that it times out in 100 ms
        xmlChangeTimer.Start();
    }

    private void xmlChangeTimer_Tick(object sender, EventArgs e)
    {
        foreach (FileSystemEventArgs eventArg in xmlFileChangedEvents.Values)
        {
            //
            //Handle the file changed event here
            //
        }
        xmlFileChangedEvents.Clear();
    }
2
ответ дан 3 December 2019 в 01:13
поделиться

Я сделал простой класс, который мне подходит. Это может быть полезно кому-то другому.

using System;
using System.IO;
using System.Timers;

namespace Demo
{
    class FileWatcher
    {
        private FileSystemWatcher watcher = new FileSystemWatcher();
        private Timer t = new Timer();

        public event EventHandler FileChanged;

        public FileWatcher()
        {
            t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
            t.Interval = 1000;
        }

        public void Start(String path)
        {
            watcher.Path = Path.GetDirectoryName(path);
            watcher.Filter = Path.GetFileName(path);
            watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime;
            watcher.EnableRaisingEvents = true;
            watcher.Changed += new FileSystemEventHandler(watcher_Changed);
        }

        void watcher_Changed(object sender, FileSystemEventArgs e)
        {
            if (!t.Enabled)
                t.Start();
        }

        void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            t.Stop();
            if (FileChanged != null)
                FileChanged(this, null);
        }
    }
}

Можно использовать так:

FileWatcher FileWatcher1 = new FileWatcher();
FileWatcher1.FileChanged += new EventHandler(FileWatcher1_FileChanged);
FileWatcher1.Start("c:\test.txt");
1
ответ дан 3 December 2019 в 01:13
поделиться

Это была сумасшедшая причуда API Win32 FindFirstChangeNotification() с первого дня (с Windows 3.x), и похоже, что FileSystemWatcher просто обертывает этот API. Подход с использованием таймера (представленный выше) является обычным обходным решением.

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

public class FileChangeMonitor
{
    private FileSystemWatcher _fsw;
    DateTime _lastEventTime;

    public event FileSystemEventHandler Changed;

    public FileChangeMonitor(string path, string filter)
    {
        _fsw = new FileSystemWatcher(path, filter);
        _fsw.Changed += new FileSystemEventHandler(_fsw_Changed);
        _fsw.EnableRaisingEvents = true;
        _fsw.NotifyFilter = NotifyFilters.LastWrite;
        _fsw.IncludeSubdirectories = false;
    }

    private void _fsw_Changed(object sender, FileSystemEventArgs e)
    {
        // Fix the FindFirstChangeNotification() double-call bug
        if (DateTime.Now.Subtract(_lastEventTime).TotalMilliseconds > 100)
        {
            _lastEventTime = DateTime.Now;
            if (this.Changed != null)
                this.Changed(sender, e);  // Bubble the event
        }
    }
}

Затем вы можете использовать FileChangeMonitor точно так же, как и FileSystemWatcher:

FileChangeMonitor fcm = new FileChangeMonitor(path, filter);
fsm.Changed += new FileSystemEventHandler(fsm_Changed);
...

Конечно, код выше обрабатывает только событие Changed и NotifyFilters.LastWrite, но вы поняли идею.

1
ответ дан 3 December 2019 в 01:13
поделиться

Независимый от платформы трюк :

// Class level variable
bool m_FileSystemWatcherIsMessy = true;

// inside call back
if (m_FileSystemWatcherIsMessy) {
    m_FileSystemWatcherIsMessy = false;
    return;
} else {
    m_FileSystemWatcherIsMessy = true;
}
1
ответ дан 3 December 2019 в 01:13
поделиться
Другие вопросы по тегам:

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