Help with File Watcher class

judge

Member
Joined
Dec 7, 2009
Messages
18
Programming Experience
Beginner
I have a simple file watcher application which watches the folder C:\. I am watching the folder so that as soon as a new file is created in C:\, it moves the newfile to a specified folder somewhere else. My problem is that if two files are dropped in the C:\ folder at the same time, my code only deals with one of the files. I would like my code to identify both files, and move both of them.

Here's some of my code:
VB.NET:
Dim folderToWatch As String = "C:\"

PrvSubMain()

watchFolder = New System.IO.FileSystemWatcher()
watchFolder.Path = folderToWatch
watchFolder.NotifyFilter = IO.NotifyFilters.FileName
AddHandler watchFolder.Created, AddressOf FileCreated
watchFolder.EnableRaisingEvents = True

End Sub

Private Sub FileCreated(ByVal source As Object, ByVal e As _
System.IO.FileSystemEventArgs)

Dim fileName As String = ""
Dim pathOfFile As String

If e.ChangeType = IO.WatcherChangeTypes.Created Then
fileName = e.Name
End If

pathOfFile = e.FullPath

If fileName = "" = False Then

[COLOR="DarkGreen"]'Pass the pathOfFile and fileName off to the MoveFile function where it will move the file to another folder..[/COLOR]
MoveFile(pathOfFile, fileName)
watchFolder.EnableRaisingEvents = False
End If

End Sub


Thankyou in advance!
 
I had a similar issue that I need to handle with a in house app. The app moves files and allows the user to enter some information on another form to be saved in a database. So here is what I did to handle multiple file created events.

This is my global that I use as a flag so that the multiple created events do not conflict with each other. There may be a better way but it was the best I could find...
VB.NET:
Dim IsAlreadyProcessing As Boolean = False

File watching event.
VB.NET:
    Private Sub fswDocTray_Created(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) Handles fswDocTray.Created

        Dim drResult As DialogResult = Windows.Forms.DialogResult.None
        If Not IsAlreadyProcessing Then
            Dim di As DirectoryInfo = New DirectoryInfo(My.Settings.MoveFilesFrom)
            drResult = ProcessAllFiles(di)

           
            'Add the dialog result which will bubble up from the DocEntry screen as either
            ' "Cancel" = not processing a document or "OK" = processed fine ok to do more.
            ' This check will allow it to continue processing more documents as long as the 
            ' returned result is OK
            If Not drResult = Windows.Forms.DialogResult.Cancel Then
                If di.GetFiles().Length > 0 Then
                    ProcessAllFiles(di)
                End If
            End If
           
         End If
    End Sub

This is where you might do your file move.
VB.NET:
    Private Function ProcessAllFiles(ByRef PassDI As DirectoryInfo) As DialogResult
        Dim returnResult As DialogResult = Windows.Forms.DialogResult.Cancel

        IsAlreadyProcessing = True
        For Each fiFile As FileInfo In PassDI.GetFiles
            If IsExtensionAssociated(fiFile.Extension) Then
                returnResult = ProcessFile(fiFile)
                If returnResult = Windows.Forms.DialogResult.Cancel Then
                    Exit For
                End If
            End If
        Next

        IsAlreadyProcessing = False
        Return returnResult
    End Function

At the very least it will give you something to think about.
 
In situations where I may have files coming in faster than the FileSystemWatcher's buffer can hold I offload to a queue.

In this example I'm just creating files and writing DateTime.Now to when the file is processed. The Thread.Sleep(2000) is there just to simulate a longer running process.

VB.NET:
Imports System.IO

Public Class Form1
    Shared folder As String = "C:\Temp\Fsw"
    Shared processor As FswProcessor
    Shared watcher As FileSystemWatcher

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        processor = New FswProcessor()
        InitFsw()
        CreateDummyFiles()
    End Sub

    Private Shared Sub InitFsw()
        watcher = New FileSystemWatcher
        watcher.Path = folder
        AddHandler watcher.Created, AddressOf watcher_Created
        watcher.EnableRaisingEvents = True
        watcher.Filter = "*.txt"
    End Sub

    Private Shared Sub CreateDummyFiles()
        For i As Integer = 0 To 100
            Using fs As New FileStream(String.Format("{0}\{1}.txt", folder, i), FileMode.Create) : End Using
        Next
    End Sub

    Private Shared Sub watcher_Created(ByVal sender As Object, ByVal e As FileSystemEventArgs)
        processor.QueueFile(e.FullPath)
    End Sub
End Class

VB.NET:
Imports System.Threading

Public Class FswProcessor
    Private workQueue As Queue(Of String)
    Private workerThread As Threading.Thread
    Private evtWaitHandle As EventWaitHandle

    Public Sub New()
        workQueue = New Queue(Of String)()
        evtWaitHandle = New AutoResetEvent(True)
    End Sub

    Public Sub QueueFile(ByVal filepath As String)
        workQueue.Enqueue(filepath)

        'Init & Start thread when 1st file is added
        If workerThread Is Nothing Then
            workerThread = New Threading.Thread(New ThreadStart(AddressOf Work))
            workerThread.Start()

            'Start thread if it's waiting
        ElseIf workerThread.ThreadState = ThreadState.WaitSleepJoin Then
            evtWaitHandle.Set()
        End If
    End Sub

    Private Sub Work()
        While True
            Dim filepath As String = DequeueFile()

            If filepath IsNot Nothing Then
                ProcessFile(filepath)
            Else
                evtWaitHandle.WaitOne() 'Wait if no files in queue
            End If
        End While
    End Sub

    Private Function DequeueFile() As String
        If workQueue.Count > 0 Then
            Return workQueue.Dequeue()
        Else
            Return Nothing
        End If
    End Function

    Private Sub ProcessFile(ByVal filepath As String)
        Using sw As New IO.StreamWriter(filepath, True)
            sw.WriteLine(String.Format("Processed @ {0}", DateTime.Now()))
        End Using
        Thread.Sleep(2000)
    End Sub
End Class
 
Matt P

Many Thansk, I'm new to Filewatcher and Threads is even newer, this has helped with an App I'm developing and I can see the benefits of doing it by a thread too
 
Back
Top