Почему FileSystemWatcher срабатывает дважды


Почему FileSystemWatcher срабатывает дважды? Есть ли простой способ исправить это? Конечно, если я обновлю или отредактирую текстовый файл, он должен сработать только один раз?

Эта ссылка здесь http://weblogs.asp.net/ashben/archive/2003/10/14/31773.aspx говорит

  1. события, вызываемые дважды-событие будет вызываться дважды, если обработчик событий (AddHander FSW.Создано, AddressOf FSW_Created) является явно указать. Это происходит потому, что по умолчанию публичные мероприятия автоматически вызовите соответствующие защищенные методы (OnChanged, OnCreated, OnDeleted, OnRenamed). Чтобы исправить эту проблему, просто удалите явный обработчик событий (AddHandler ...).

Что означает "удалить явный обработчик событий"?

Imports System.IO

Public Class Form2

    Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed

        'this fires twice
        MessageBox.Show("test")

    End Sub

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        FileSystemWatcher1.Path = "C:UserscDesktoptest"
        FileSystemWatcher1.NotifyFilter = NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName Or NotifyFilters.CreationTime

        FileSystemWatcher1.IncludeSubdirectories = False
        FileSystemWatcher1.Filter = "text.txt"

    End Sub

End Class
3 8

3 ответа:

Обновление:

Я придумал 2 решения. Один использует потоки, а другой-нет.

без резьбы:

Imports System.IO

Public Class Form1
    Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed
        Dim watcher As System.IO.FileSystemWatcher = sender
        watcher.EnableRaisingEvents = False

        'Do work here while new events are not being raised.
        MessageBox.Show("Test")

        watcher.EnableRaisingEvents = True 'Now we can begin watching for new events.

    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        FileSystemWatcher1.Path = "C:\Users\c\Desktop\test"
        FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
        FileSystemWatcher1.IncludeSubdirectories = False
        FileSystemWatcher1.Filter = "test.txt"


    End Sub

    Private Sub FileSystemWatcher_OnChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

    End Sub

End Class

Это решение (без резьбы) устанавливает наблюдатель.EnableRaisingEvents к ложному. Именно после этого момента вы обычно обрабатываете все файлы, которые были затронуты (или изменены). Затем он устанавливает EnableRaisingEvents обратно в True после завершения работы.

с резьбой:

Imports System.IO

Public Class Form1
    Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed
        FileSystemWatcher1.EnableRaisingEvents = False
        Threading.Thread.Sleep(250)
        FileSystemWatcher1.EnableRaisingEvents = True


        MessageBox.Show("test")


    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        FileSystemWatcher1.Path = "C:\Users\c\Desktop\test"
        FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
        FileSystemWatcher1.IncludeSubdirectories = False
        FileSystemWatcher1.Filter = "test.txt"


    End Sub

    Private Sub FileSystemWatcher_OnChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

    End Sub

End Class

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

Проверьте e.тип изменения. Я думаю, вы получаете два разных уведомления. Возможно, LastAccess и LastModified. В таком случае, это ожидаемое поведение.

Сегодня я врезался в FileSystemWatcher и нашел этот сайт. Предложил Нить.Сон не может полностью устранить проблему. Тестировался с быстрым целочисленным счетчиком. И блокирует пользовательский интерфейс. Наиболее проблематичным является автозагрузки, она проскальзывала Через на 5s. Тогда я поставил FileSystemWatcher1.EnableRaisingEvents = False немедленно в TimerWatcherChanged.Поставьте галочку и больше никогда не включайте... Но на удивление счетчик все-таки догнал-до 4-х событий! Я хотел бы поделиться своим решением, неблокирующим, с регулируемым таймером. Обратная связь есть добро пожаловать.

Imports System.IO

Imports System.Diagnostics

Public Class Form1
  Dim fileName As String
  Dim Fsw_counter As Integer
  WithEvents TimerWatcherChanged As New Windows.Forms.Timer
  WithEvents TimerTest As New Windows.Forms.Timer

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    TimerWatcherChanged.Interval = 100
    TimerTest.Interval = 100 : TimerTest.Start()
    TextBox1.Text = "C:\Downloads\New Text Document.txt"
    TextBox1.SelectionStart = TextBox1.Text.Length
    WatcherSetup()
  End Sub

  Sub WatcherSetup()
    fileName = TextBox1.Text
    FileSystemWatcher1.IncludeSubdirectories = False
    FileSystemWatcher1.Path = Path.GetDirectoryName(fileName)
    FileSystemWatcher1.Filter = Path.GetFileName(fileName)
    FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
    FileSystemWatcher1.EnableRaisingEvents = True
  End Sub

  Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
    WatcherSetup()
  End Sub

  Private Sub FileSystemWatcher1_Changed(sender As Object, e As FileSystemEventArgs) Handles FileSystemWatcher1.Changed
    If TimerWatcherChanged.Enabled = False Then
      TimerWatcherChanged.Enabled = True
      Fsw_counter += 1
      ' ***** Your WATCH Code put here... *****
    End If
  End Sub

  Private Sub TimerWatcherChanged_Tick(sender As Object, e As EventArgs) Handles TimerWatcherChanged.Tick
    TimerWatcherChanged.Enabled = False
  End Sub

  Private Sub TimerTest_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimerTest.Tick
    TextBox2.Text = "Changed: " & Fsw_counter
    If TimerWatcherChanged.Enabled = True Then
      TextBox2.BackColor = Color.Red
    Else
      TextBox2.BackColor = Color.LawnGreen
    End If
  End Sub
End Class