Link to home
Start Free TrialLog in
Avatar of conceptdata
conceptdataFlag for Denmark

asked on

Windows Form - FileSystemWatcher loop until Prigram exit

Hi

I have a FileSystemWatcher in Form_Load
Is it possible to make a loop of the FileSystemWatcher until the program closes manually.

Dim watcher As New FileSystemWatcher()
        watcher.Path = My.Settings.FromPath
        watcher.Filter = My.Settings.FileType
        '"*.xml";
        watcher.NotifyFilter = NotifyFilters.FileName
        AddHandler watcher.Changed, New FileSystemEventHandler(AddressOf watchActivate)
        AddHandler watcher.Created, New FileSystemEventHandler(AddressOf watchActivate)
        watcher.EnableRaisingEvents = True

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Éric Moreau
Éric Moreau
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Don't quite understand what you mean... the watcher IS watching everything until you stop it or until the program closes.
Any changes that happen will fire the events you hooked up with watchActivate, what are you looking to loop through?
Avatar of conceptdata

ASKER

Maybe it because I have my FileSystemWatcher in my Form1_Load

See attached code. ??
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'If bShowForm = False Then
        '    Me.WindowState = FormWindowState.Minimized
        '    Me.Visible = False
        '    nfi.Visible = True
        '    nfi.ShowBalloonTip(2000, "FilesMoveApp", "Programmet kører", ToolTipIcon.Info)
        'End If

        Dim filesPresent As [String]() = Directory.GetFiles(My.Settings.FromPath)
        Dim filesPresent1 As [String]() = Directory.GetFiles(My.Settings.FromPath)

        Dim watcher As New FileSystemWatcher()
        watcher.Path = My.Settings.FromPath
        watcher.Filter = My.Settings.FileType
        '"*.xml";
        watcher.NotifyFilter = NotifyFilters.FileName
        AddHandler watcher.Changed, New FileSystemEventHandler(AddressOf watchActivate)
        AddHandler watcher.Created, New FileSystemEventHandler(AddressOf watchActivate)
        watcher.EnableRaisingEvents = True

        'foreach (String filename in filesPresent1)
        '    LogMessageToFile(FilesMoveService.Properties.Settings.Default.FromPath + "\\" + Path.GetFileName(filename) + " --- " + FilesMoveService.Properties.Settings.Default.ToPath + "\\" + Path.GetFileName(filename));
        For Each filename As [String] In filesPresent
            FilesMove(My.Settings.FromPath + "\" & Path.GetFileName(filename), My.Settings.ToPath + "\" & Path.GetFileName(filename))
        Next
    End Sub

Open in new window

So if I understand this, when the form loads, you want to move the entire contents of the directory out into the "TO" path, and then while the program is running, anytime an additinal file is put there, move that as well?

If so, keep the initial for loop as you have it:
For Each filename As [String] In filesPresent


But then add that same line of code into the watchActivate function.

The first for you have will clear out the existing files, then everytime a new file is added, the watcher will trigger the watchActivate function, which will again loop through and move all the files.
I had some problems with this component for which I have found workarounds (check my article)
Can you show my with my existing code :)
This is my whole code :
Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'If bShowForm = False Then
        '    Me.WindowState = FormWindowState.Minimized
        '    Me.Visible = False
        '    nfi.Visible = True
        '    nfi.ShowBalloonTip(2000, "FilesMoveApp", "Programmet kører", ToolTipIcon.Info)
        'End If

        Dim filesPresent As [String]() = Directory.GetFiles(My.Settings.FromPath)

        Dim watcher As New FileSystemWatcher()
        watcher.Path = My.Settings.FromPath
        watcher.Filter = My.Settings.FileType
        '"*.xml";
        watcher.NotifyFilter = NotifyFilters.FileName
        AddHandler watcher.Changed, New FileSystemEventHandler(AddressOf watchActivate)
        AddHandler watcher.Created, New FileSystemEventHandler(AddressOf watchActivate)
        watcher.EnableRaisingEvents = True

        For Each filename As [String] In filesPresent
            FilesMove(My.Settings.FromPath + "\" & Path.GetFileName(filename), My.Settings.ToPath + "\" & Path.GetFileName(filename))
        Next
    End Sub


    Private Shared Sub watchActivate(ByVal source As Object, ByVal e As FileSystemEventArgs)
        'LogMessageToFile(e.FullPath + " -- " + FilesMoveService.Properties.Settings.Default.ToPath + e.Name);
        FilesMove(e.FullPath, My.Settings.ToPath + "\" & e.Name)
    End Sub

    Private Shared Sub FilesMove(ByVal FromFileName As String, ByVal ToFileName As String)
        WaitReady(FromFileName)
        LogMessageToFile("Fil flyttet : [" & FromFileName & "] -> [" & ToFileName & "]")
        If File.Exists(ToFileName) Then
            File.Delete(ToFileName)
        End If
        LogMessageToFile("Fil slettet : [" & ToFileName & "], er slettet da den nye fil har samme navn.")

        File.Move(FromFileName, ToFileName)
    End Sub

    Public Shared Sub WaitReady(ByVal fileName As String)
        While True
            Try
                Using stream As Stream = System.IO.File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
                    If stream IsNot Nothing Then
                        System.Diagnostics.Trace.WriteLine(String.Format("Output file {0} ready.", fileName))
                        Exit Try
                    End If
                End Using
            Catch ex As FileNotFoundException
                System.Diagnostics.Trace.WriteLine(String.Format("Output file {0} not yet ready ({1})", fileName, ex.Message))
            Catch ex As IOException
                System.Diagnostics.Trace.WriteLine(String.Format("Output file {0} not yet ready ({1})", fileName, ex.Message))
            Catch ex As UnauthorizedAccessException
                System.Diagnostics.Trace.WriteLine(String.Format("Output file {0} not yet ready ({1})", fileName, ex.Message))
            End Try
            Thread.Sleep(500)
        End While
    End Sub

    Private Shared ReadOnly LOG_FILENAME As String = My.Settings.LogFile

    Public Shared Sub LogMessageToFile(ByVal msg As String)
        msg = String.Format("{0:G}: {1}" & vbCr & vbLf, DateTime.Now, msg)
        File.AppendAllText(LOG_FILENAME, msg)
    End Sub

End Class

Open in new window

Replace the single File.Move command you have in the watchActivate window with the for loop that you put in the load event.
The main issue with the FileSystemWatcher, is that it's not guaranteed to return every file.  If you happen to be copying a lot of files at once into the target directory, there's a good chance you'll just get a few notifications, NOT one for every file.

Safeguard against that, is each time the event is triggered, look for ALL files and move manually.
Hi again
I used emoreau's solution, and modified it for my purpose.

Thanks both ..