jj: filewatcher

This commit is contained in:
Jonathan Jenne 2019-02-06 15:31:22 +01:00
parent a1c96731ef
commit fedc45a88b
5 changed files with 174 additions and 72 deletions

View File

@ -1,25 +1,33 @@
Imports System.IO
Imports DigitalData.Modules.Filesystem
Imports DigitalData.Modules.Filesystem.FileWatcherFilters
Imports DigitalData.Modules.Logging
Public Class FileWatcher
' Internals
Private ReadOnly _Logger As Logger
Private ReadOnly _Watchers As List(Of FileSystemWatcher)
Private ReadOnly _Files As Dictionary(Of String, FileProperties)
Private ReadOnly _Files As Dictionary(Of String, FileWatcherProperties)
Private ReadOnly _Filters As List(Of BaseFileFilter)
' Options
Private _Path As String
Public OfficeFilters As New List(Of String) From {"docx", "xlsx", "pptx"}
' Public Events
Public Event FileSaved(ByVal FullName As String, ByVal IsSpecial As Boolean)
Public Sub New(LogConfig As LogConfig, Path As String)
Public Sub New(LogConfig As LogConfig, Path As String, Optional Filters As List(Of BaseFileFilter) = Nothing)
_Logger = LogConfig.GetLogger()
_Files = New Dictionary(Of String, FileProperties)
_Files = New Dictionary(Of String, FileWatcherProperties)
_Watchers = New List(Of FileSystemWatcher)
_Filters = IIf(IsNothing(Filters), GetDefaultFilters(), Filters)
_Path = Path
For Each oFilePath As String In Directory.EnumerateFiles(_Path)
For Each oFilePath In Directory.EnumerateFiles(_Path)
Try
If IO.File.Exists(oFilePath) Then
_Files.Add(oFilePath, New FileProperties With {
_Files.Add(oFilePath, New FileWatcherProperties With {
.CreatedAt = DateTime.Now,
.ChangedAt = Nothing
})
@ -31,58 +39,10 @@ Public Class FileWatcher
Next
End Sub
Public Sub Add(Filter As String, Optional SpecialTreatmentFilters As List(Of String) = Nothing)
Public Sub Add(Filter As String)
_Watchers.Add(CreateWatcher(Filter))
End Sub
Public Sub Add(Filters As List(Of String), Optional SpecialTreatmentFilters As List(Of String) = Nothing)
For Each oFilter In Filters
_Watchers.Add(CreateWatcher(oFilter))
Next
End Sub
Private Function CreateWatcher(Filter As String)
Dim oWatcher = New FileSystemWatcher() With {
.Path = _Path,
.Filter = Filter,
.NotifyFilter = NotifyFilters.CreationTime _
Or NotifyFilters.LastAccess _
Or NotifyFilters.LastWrite _
Or NotifyFilters.Size _
Or NotifyFilters.FileName _
Or NotifyFilters.Attributes
}
AddHandler oWatcher.Created, AddressOf HandleFileCreated
AddHandler oWatcher.Changed, AddressOf HandleFileChanged
AddHandler oWatcher.Deleted, AddressOf HandleFileDeleted
AddHandler oWatcher.Renamed, AddressOf HandleFileRenamed
Return oWatcher
End Function
Private Sub HandleFileCreated(sender As Object, e As FileSystemEventArgs)
_Files.Add(e.FullPath, New FileProperties())
_Logger.Info("[Created] " & e.FullPath)
End Sub
Private Sub HandleFileChanged(sender As Object, e As FileSystemEventArgs)
_Files.Item(e.FullPath).ChangedAt = DateTime.Now
_Logger.Info("[Changed] " & e.FullPath)
End Sub
Private Sub HandleFileDeleted(sender As Object, e As FileSystemEventArgs)
_Files.Remove(e.FullPath)
_Logger.Info("[Removed] " & e.FullPath)
End Sub
Private Sub HandleFileRenamed(sender As Object, e As RenamedEventArgs)
Dim oProperties = _Files.Item(e.OldFullPath)
_Files.Remove(e.OldFullPath)
_Files.Add(e.FullPath, oProperties)
' Soll eine umbenannte datei als NEU gelten?
_Logger.Info("[Renamed] {0} --> {1}", e.OldFullPath, e.FullPath)
End Sub
Public Sub Start()
For Each oWatcher In _Watchers
oWatcher.EnableRaisingEvents = True
@ -98,13 +58,75 @@ Public Class FileWatcher
Next
End Sub
Public Class FileProperties
Public CreatedAt As DateTime
Public ChangedAt As DateTime
Private Function GetDefaultFilters()
Return New List(Of BaseFileFilter) From {
New TempFileFilter,
New OfficeFileFilter
}
End Function
Private Function CreateWatcher(Filter As String)
Dim oWatcher = New FileSystemWatcher() With {
.Path = _Path,
.Filter = Filter,
.NotifyFilter = NotifyFilters.LastAccess _
Or NotifyFilters.LastWrite _
Or NotifyFilters.FileName _
Or NotifyFilters.Size _
Or NotifyFilters.FileName _
Or NotifyFilters.Attributes
}
AddHandler oWatcher.Created, AddressOf HandleFileCreated
AddHandler oWatcher.Changed, AddressOf HandleFileChanged
AddHandler oWatcher.Deleted, AddressOf HandleFileDeleted
AddHandler oWatcher.Renamed, AddressOf HandleFileRenamed
Return oWatcher
End Function
Private Sub HandleFileCreated(sender As Object, e As FileSystemEventArgs)
_Files.Add(e.FullPath, New FileWatcherProperties())
_Logger.Debug("[Created] " & e.FullPath)
End Sub
''' <summary>
''' This may fire twice for a single save operation,
''' see: https://blogs.msdn.microsoft.com/oldnewthing/20140507-00/?p=1053/
''' </summary>
Private Sub HandleFileChanged(sender As Object, e As FileSystemEventArgs)
_Files.Item(e.FullPath).ChangedAt = DateTime.Now
_Logger.Debug("[Changed] " & e.FullPath)
Dim oShouldRaiseSave As Boolean = Not _Filters.Any(Function(oFilter)
Return oFilter.ShouldFilter(e)
End Function)
If oShouldRaiseSave Then
RaiseEvent FileSaved(e.FullPath, False)
End If
End Sub
Private Sub HandleFileDeleted(sender As Object, e As FileSystemEventArgs)
_Files.Remove(e.FullPath)
_Logger.Debug("[Removed] " & e.FullPath)
End Sub
Private Sub HandleFileRenamed(sender As Object, e As RenamedEventArgs)
Dim oProperties = _Files.Item(e.OldFullPath)
_Files.Remove(e.OldFullPath)
_Files.Add(e.FullPath, oProperties)
' Soll eine umbenannte datei als NEU gelten?
Dim oShouldRaiseSave = _Filters.Any(Function(oFilter)
Return oFilter.ShouldRaiseSave(e)
End Function)
If oShouldRaiseSave Then
RaiseEvent FileSaved(e.OldFullPath, True)
End If
_Logger.Debug("[Renamed] {0} --> {1}", e.OldFullPath, e.FullPath)
End Sub
Public Sub New()
CreatedAt = DateTime.Now
ChangedAt = Nothing
End Sub
End Class
End Class

View File

@ -0,0 +1,61 @@
Imports System.IO
''' <summary>
''' Built-in filters for FileWatcher that are useful for correctly detecting changes on Office documents (currently Office 2016)
''' </summary>
Public Class FileWatcherFilters
''' <summary>
''' Base Filter that all filters must inherit from
''' Provides two functions that may be overridden and some useful file extension lists
''' </summary>
Public MustInherit Class BaseFileFilter
Public TempFiles As New List(Of String) From {".tmp", ""}
Public Overridable Function ShouldFilter(e As FileSystemEventArgs) As Boolean
Return False
End Function
Public Overridable Function ShouldRaiseSave(e As RenamedEventArgs) As Boolean
Return False
End Function
End Class
''' <summary>
''' Simple Filter that filters changes made on temporary files
''' </summary>
Public Class TempFileFilter
Inherits BaseFileFilter
Public Overrides Function ShouldFilter(e As FileSystemEventArgs) As Boolean
Dim oFileInfo As New FileInfo(e.FullPath)
Return TempFiles.Contains(oFileInfo.Extension)
End Function
End Class
''' <summary>
''' Filter to detect changes on Office files
''' </summary>
Public Class OfficeFileFilter
Inherits BaseFileFilter
Public OfficeFiles As New List(Of String) From {".docx", ".pptx", ".xlsx"}
Public Overrides Function ShouldFilter(e As FileSystemEventArgs) As Boolean
Dim oFileInfo As New FileInfo(e.FullPath)
Return OfficeFiles.Contains(oFileInfo.Extension) And oFileInfo.Name.StartsWith("~")
End Function
Public Overrides Function ShouldRaiseSave(e As RenamedEventArgs) As Boolean
Dim oIsTransform = OfficeFiles.Any(Function(Extension As String)
Return e.OldName.EndsWith(Extension)
End Function)
' Check if it is renamed to a temp file
Dim oIsTempFile = TempFiles.Any(Function(Extension)
Return e.Name.EndsWith(Extension)
End Function)
Return oIsTransform And oIsTempFile
End Function
End Class
End Class

View File

@ -0,0 +1,10 @@
Public Class FileWatcherProperties
Public Property CreatedAt As DateTime
Public Property ChangedAt As DateTime
Public ReadOnly Property HasChanged As Boolean
Public Sub New()
CreatedAt = DateTime.Now
ChangedAt = Nothing
HasChanged = False
End Sub
End Class

View File

@ -81,6 +81,8 @@
<Compile Include="File.vb" />
<Compile Include="FileContainerInner.vb" />
<Compile Include="FileWatcher.vb" />
<Compile Include="FileWatcherFilters.vb" />
<Compile Include="FileWatcherProperties.vb" />
<Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>

View File

@ -1,30 +1,37 @@
Imports System.ComponentModel
Imports System.IO
Imports DigitalData.Modules.Filesystem
Imports DigitalData.Modules.Filesystem.FileWatcherFilters
Imports DigitalData.Modules.Logging
Public Class FolderWatcher
Private _LogConfig As LogConfig
Private _Logger As Logger
Private _Watcher As FileWatcher
Public Sub FileCreated(_sender As Object, _e As FileSystemEventArgs)
ListBox1.Items.Add($"File created: {_e.FullPath}")
End Sub
Public Sub FileChanged(_sender As Object, _e As FileSystemEventArgs)
ListBox1.Items.Add($"File changed: {_e.FullPath}")
End Sub
<STAThread()>
Private Sub FolderWatcher_Load(sender As Object, e As EventArgs) Handles Me.Load
_LogConfig = New LogConfig(LogConfig.PathType.CurrentDirectory, Nothing, "MAIN")
_Watcher = New FileWatcher(_LogConfig, "E:\Watcher")
_LogConfig.Debug = True
_Logger = _LogConfig.GetLogger()
Dim oFilters As New List(Of BaseFileFilter) From {
New TempFileFilter,
New OfficeFileFilter
}
_Watcher = New FileWatcher(_LogConfig, "E:\Watcher", oFilters)
_Watcher.Add("*.*")
AddHandler _Watcher.FileSaved, AddressOf HandleFileSaved
_Watcher.Start()
End Sub
Private Sub HandleFileSaved(FullName As String, IsSpecial As Boolean)
_Logger.Info("{1}File Saved: {0}", FullName, IIf(IsSpecial, "Special ", ""))
End Sub
Private Sub FolderWatcher_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
_Watcher.Stop()
End Sub