appending an entry number to FileSystemWatcher output

前端 未结 1 1824
借酒劲吻你
借酒劲吻你 2021-01-26 18:29

Okay,

Probably going to be seen as an extremely amature post here, I\'m not really skilled in VB or much of a programmer but i\'m on a \"learn by doing\" drive.

<
相关标签:
1条回答
  • 2021-01-26 18:59

    This is a class that inherits from FileSystemWatcher.
    It takes care of the configuration, enables and disables the raising of events and has basic logging and reporting capabilities.

    Configuration of FileSystemWatcher:

    .BeginInit() - .EndInit()
    BeginInit() is used to prevent the raising of events before the FileSystemWatcher setup is completed.

    .SynchronizingObject
    Set the SynchronizingObject to a Form component. Since the FileSystemWatcher events are marshalled from the system thread pool, this ensures that the event delegates are called on the same thread where the component is created.
    If SynchronizingObject is null, accessing the component may result in an Exception or, worse, in a silent failure.

    .InternalBufferSize
    The internal buffer is used to store the events register and a file path. A buffer larger that the default (8192 bytes) can prevent a buffer overflow, which compromises the rising of events. Here it's set to 32768 bytes.

    .Path
    For network drives/shares use UNC Paths.

    How to use it:

    Define a public object that references the FileWatcher Class:

    Public FileWatch As FileWatcher
    

    Then you can initialize it whenever you need it:

    FileWatch = New FileWatcher("[Path to watch]", 
                                "*",  'All files
                                "[Path to LogFile]", 
                                Me,   'Synchronizing Object
                                Me.[TextBox control used as monitor])
    


    [TextBox control used as monitor] can be Nothing if none is used.

    The FileWatcher doesn't immediately start to raise/log events; the EnableRaisingEvents property is set to False in the initialization method.
    You can start and stop it's activity with its methods:

    Me.FileWatch.StartWatcher()
    Me.FileWatch.StopWatcher()
    


    Starting and stopping the FileWatcher is a registered (logged) activity.
    A List(Of DateTime) is used to store these events. See the FW_EventLogger Class.

    Other stored informations are:

    • Number of files Deleted.
    • Number of files Created
    • Overall number of registered events (for comparison).
    • Size of the Log File.

    The ActivityReport() property returns a simple report:

    Dictionary(Of String, String) = FileWatcher.ActivityReport()
    


    This is what the Log File looks like:

    00000001 - 2018/02/28 21:00:25 - File D:\Temp\New Text Document.txt has been created
    00000002 - 2018/02/28 21:00:29 - File D:\Temp\New Microsoft Access Database.accdb has been created
    00000003 - 2018/02/28 21:00:34 - File D:\Temp\New WinZip File.zip has been created
    00000004 - 2018/02/28 21:00:44 - File D:\Temp\New Microsoft Access Database.accdb has been deleted
    00000005 - 2018/02/28 21:00:44 - File D:\Temp\New Text Document.txt has been deleted
    00000006 - 2018/02/28 21:00:44 - File D:\Temp\New WinZip File.zip has been deleted
    


    Limitatons: If requested (a TextBox control reference is passed to the class initialization), the UI is updated synchronously through a synchronization object. If the UI thread is busy for some reason, the events the underlying FileSystemWatcher is buffering will pile up. This can (and since it can it will) cause the loss of events. This is the reason why the internal buffer is set to 4x the default. Anyway, it won't ever be enough if the monitored activity is high. In normal condition, it can handle 10/sec. events without problem. Beyond that, an asynchronous proxy method that makes use a FIFO queue buffer must be placed between the event listeners and the data consumers.

    Built on:

    Visual Studio 2013, Update 5
    .Net Framework 4.7.1
    

    Updated to:

    Visual Studio 2017, 15.8.4
    .Net Framework 4.7.1
    


    Imports System.Collections.Generic
    Imports System.IO
    Imports System.Windows.Forms
    
    
    Public Class FileWatcher
        Inherits FileSystemWatcher
    
        Private EventLogger As FW_EventLogger
        Private Prompt As TextBox = Nothing
    
        Public Sub New()
            Me.New("", "", "", Nothing, Nothing)
        End Sub
    
        Public Sub New(fswPath As String, fswFilter As String, logFile As String, SyncObject As Form, SyncPrompt As TextBox)
            Me.Prompt = SyncPrompt
            Me.EventLogger = New FW_EventLogger With {.LogFileName = logFile}
    
            SetupFileWatcher(fswPath, fswFilter, SyncObject)
        End Sub
    
        Public Sub StartWatcher()
            Me.EventLogger.TimeStart.Add(DateTime.UtcNow)
            If Me.Prompt IsNot Nothing Then
                Me.Prompt.AppendText(String.Format("Logger Start Time: {0}" +
                                     Environment.NewLine, DateTime.UtcNow.ToString()))
            End If
            Me.EnableRaisingEvents = True
        End Sub
    
        Public Sub StopWatcher()
            Me.EnableRaisingEvents = False
            Me.EventLogger.TimeStop.Add(DateTime.UtcNow)
            If Me.Prompt IsNot Nothing Then
                Me.Prompt.AppendText(String.Format("Logger Stop Time: {0}" +
                                     Environment.NewLine, DateTime.UtcNow.ToString()))
            End If
        End Sub
    
        Public ReadOnly Property ActivityReport() As Dictionary(Of String, String)
            Get
                Return Me.CreateActivityReport()
            End Get
        End Property
    
        Public Property PromptControl As TextBox
            Get
                Return Me.Prompt
            End Get
            Set(value As TextBox)
                Me.Prompt = value
            End Set
        End Property
    
    
        Public Sub SetupFileWatcher(fwPath As String, fwFilter As String, SyncObject As Form)
            If fwPath.Length = 0 Then
                Return
            End If
    
            Me.BeginInit()
            Me.SynchronizingObject = SyncObject
            Me.InternalBufferSize = 32768
            Me.IncludeSubdirectories = True
            Me.Filter = fwFilter
            Me.Path = fwPath
            Me.NotifyFilter = NotifyFilters.FileName Or NotifyFilters.CreationTime
            Me.EnableRaisingEvents = False
    
            'Set the handler to the events you want to receive
            AddHandler Me.Created, New FileSystemEventHandler(AddressOf Me.OnCreated)
            AddHandler Me.Deleted, New FileSystemEventHandler(AddressOf Me.OnDeleted)
            'The other events, should they become necessary.
            'this.Changed += new FileSystemEventHandler(this.OnChanged);
            'this.Renamed += new RenamedEventHandler(this.OnRenamed);
    
            Me.EndInit()
        End Sub
    
        Private Function CreateActivityReport() As Dictionary(Of String, String)
            With Me.EventLogger
                Dim log As New Dictionary(Of String, String)
                log.Add("Created", .FileCreated.ToString())
                log.Add("Deleted", .FileDeleted.ToString())
                log.Add("TotalEvents", .EventsLogged.ToString())
                log.Add("LogFileSize", If(File.Exists(.LogFileName), New FileInfo(.LogFileName).Length.ToString(), "N/A"))
                log.Add("StartTime", If(.TimeStart.Count > 0, .TimeStart.First().ToString(), "Not Started"))
                log.Add("LastStopTime", If(.TimeStop.Count > 0, .TimeStop.Last().ToString(), "Never"))
                log.Add("Status", If(Me.EnableRaisingEvents = True, "Running", "Stopped"))
                Return log
            End With
        End Function
    
        Protected Overloads Sub OnCreated(sender As Object, e As FileSystemEventArgs)
            Dim Msg As String = "File " & e.FullPath & " has been created"
            Me.EventLogger.Update(Msg, FW_EventLogger.EventType.FileCreated)
            If Me.Prompt IsNot Nothing Then
                Me.Prompt.AppendText(Msg + Environment.NewLine)
                Me.Prompt.ScrollToCaret()
            End If
        End Sub
    
        Protected Overloads Sub OnDeleted(sender As Object, e As FileSystemEventArgs)
            Dim Msg As String = "File " & e.FullPath & " has been deleted"
            Me.EventLogger.Update(Msg, FW_EventLogger.EventType.FileDeleted)
            If Me.Prompt IsNot Nothing Then
                Me.Prompt.AppendText(Msg + Environment.NewLine)
                Me.Prompt.ScrollToCaret()
            End If
        End Sub
    
        'The Event Logger Class
        Private Class FW_EventLogger
    
            Sub New()
                Me.TimeStart = New List(Of DateTime)
                Me.TimeStop = New List(Of DateTime)
            End Sub
    
            Public Enum EventType As Integer
                FileCreated = 0
                FileDeleted
            End Enum
    
            Public Property FileDeleted As Integer
            Public Property FileCreated As Integer
            Public Property EventsLogged As Integer
            Public Property TimeStart As List(Of DateTime)
            Public Property TimeStop As List(Of DateTime)
            Public Property LogFileName As String
    
            Public Sub Update(NewEvent As String, TypeOfEvent As EventType)
    
                If Me.LogFileName <> String.Empty Then
                    If TypeOfEvent = EventType.FileCreated Then Me.FileCreated += 1
                    If TypeOfEvent = EventType.FileDeleted Then Me.FileDeleted += 1
                    Me.EventsLogged += 1
                    Using LogFileWriter As StreamWriter = New StreamWriter(Me.LogFileName, True, Encoding.UTF8)
                        LogFileWriter.WriteLine(Me.EventsLogged.ToString().PadLeft(8, "0"c) +
                                                " - {0} - {1}", DateTime.UtcNow.ToString("yyyy/MM/dd hh:mm:ss"), NewEvent)
                    End Using
                End If
            End Sub
        End Class
    
    End Class
    
    0 讨论(0)
提交回复
热议问题