File Copier and Verifier Threads

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • wolfenstein
    New Member
    • Mar 2008
    • 25

    File Copier and Verifier Threads

    Hi,

    I'm working on an application that copies the files the moment these are created in the directory and paste's to some remote place.
    The thing that is making some problem; i want this process in two threads, one to copy the file and the other to verify that its copied perfectly. these threads should run simultaneously so that the moment the file copied it should be verfied as well.

    I have done with the both component but how to implement them in threads, im stuck. is there any best example i can use?
    Really need some professional support.
    Thanks!
  • vanc
    Recognized Expert New Member
    • Mar 2007
    • 211

    #2
    Originally posted by wolfenstein
    Hi,

    I'm working on an application that copies the files the moment these are created in the directory and paste's to some remote place.
    The thing that is making some problem; i want this process in two threads, one to copy the file and the other to verify that its copied perfectly. these threads should run simultaneously so that the moment the file copied it should be verfied as well.

    I have done with the both component but how to implement them in threads, im stuck. is there any best example i can use?
    Really need some professional support.
    Thanks!
    There are many ways to deal with your issue. If you research a bit about threading, I believe you can easily synchronize between threads. You can make a thread wait till the other thread conduct its work or you can lock the next resource until the other thread verify the old resource, blah blah blah.
    Looking for Thread Synchronization , it will help. Cheers.

    Comment

    • balabaster
      Recognized Expert Contributor
      • Mar 2007
      • 798

      #3
      Your question may seem simple at first glance, but really, you've asked many questions:

      Q: What should you use to copy the files?
      A: System.IO.File. Copy(SourceFile , DestinationFile )

      Q: What should you use to monitor and see if files are added or changed?
      A: System.IO.FileS ystemWatcher

      Q: How do you make sure the file copied properly?
      A: Use System.Security .Cryptography to generate an MD5 signature for the original file, do the same for the copy. If the MD5 is the same, two files are identical - the copy was successful.

      Q: How do you achieve asynchronously?
      A: Use System.Threadin g to process asynchronously. Things to watch out for - the filesystemwatch er flags multiple events for a single file change/creation - so you have to code a queuing system to prevent needless superfluous copies. It seems to me that the copy and the verification process need not be in two separate threads. You can't verify the copy is perfect until it's been copied - so you may as well do that all in a single process.

      Q: How do you spin off a new thread?
      A:
      [Code=vb]Dim FileName As String = "FileToCopy.txt "
      Dim oThrd As New System.Threadin g.Thread(Addres sOf MyWorkerMethod)
      oThrd.Start(Fil eName)

      Private Sub MyWorkerMethod( ByVal Args As Object)

      'Copy file and verify copy

      End Sub[/Code]

      I hope all that points you in the right direction...

      Comment

      • wolfenstein
        New Member
        • Mar 2008
        • 25

        #4
        Thanks,
        The guidelines are useful and using this approach i can explain some further points as well.

        1 - This copy process should be done by the Window Service and the copy will be executed on the network.

        2 - I need some messages among the threads; i.e. i have three threads;

        a) - SourceQueue Thread:- This thread makes a queue for all the files when these were created.

        b) - Copier Thread:- This thread reads the SourceQueue Thread and whenever a new file is available, this thread copies it to the destination. Then informs the Verifier thread to verify the copied file and gets back to the SourceQueue to get another file.

        c) - Verifier Thread:- This thread waits for the Copier Thread and when gets the message then verifies the copied file and update the SourceQueue Thread (Or some DB Location) that the file has been verified successfully.

        This is the architecture im looking for; the major issue in this approach is the messaging among the threads. Also the copier sends the confirmation when it completely copies the file.
        One more issue that what if the file is in use by the other user when copier tries to copy it? And when it gets the file; the file must be locked so that cant be used by any other user during the copy/move. (Exclusive Access)

        I think now you can have a better view on this approach.

        Please advice!

        Comment

        • wolfenstein
          New Member
          • Mar 2008
          • 25

          #5
          Adding one more approach; that can we have a shared location where these three threads post their status and get their next task. I dont think that should be the Thread Pool as i only like to have three threads that perform all the stuff.

          If we use this approach then what should be this shared location; i.e. what is the most feasible option for this;
          - An In-Memory List/ Array
          - Database table
          - MSMQ

          What should be the best way and how i can get this done; kindly suggest?

          Comment

          • wolfenstein
            New Member
            • Mar 2008
            • 25

            #6
            Hi All!

            Any master suggestions, reply, comments, best practices?

            Comment

            • balabaster
              Recognized Expert Contributor
              • Mar 2007
              • 798

              #7
              It seems that the only issue you're now facing is how to pass messages and how to trigger a thread to start...rather than messaging between threads, correct?

              The code I posted above shows you how to do this.

              I would use some variation of the following mechanism (I've also attached the VB Module that I wrote - just remove the .txt extension to use it). It's a quick hack that needs a couple of bits...but it does the core of what you're after. I'd imagine you'd want a MaximumRetries property so that it doesn't keep retrying failed files infinitely which it will do currently. But that should get you going in the right direction.

              [Code=vb]Imports System.Security .Cryptography
              Imports System.Threadin g
              Imports System.Text
              Imports System.IO

              Module Module1

              Class BinaryCopyObjec t

              Private _File1 As String
              Private _File2 As String

              Public Property File1() As String
              Get
              Return _File1
              End Get
              Set(ByVal value As String)
              _File1 = value
              End Set
              End Property

              Public Property File2() As String
              Get
              Return _File2
              End Get
              Set(ByVal value As String)
              _File2 = value
              End Set
              End Property

              Public Shared Function Compare(ByVal File1 As String, ByVal File2 As String) As Boolean
              Dim md5 As MD5CryptoServic eProvider = New MD5CryptoServic eProvider
              md5.ComputeHash (File.ReadAllBy tes(File1))
              Dim hash1 As Byte() = md5.Hash
              md5.ComputeHash (System.IO.File .ReadAllBytes(F ile2))
              Dim hash2 As Byte() = md5.Hash
              Return (Convert.ToBase 64String(hash1) = Convert.ToBase6 4String(hash2))
              End Function

              Public Function IsMatch() As Boolean
              Return Compare(_File1, _File2)
              End Function
              End Class

              Private InputDirectory As String = "C:\AppTesting\ Input"
              Private OutputDirectory As String = "C:\AppTesting\ Output"
              Private ContinueProcess As New Threading.Manua lResetEvent(Fal se)
              Private ProcessQueue As New Queue(Of String)
              Private StopProcessingF lag As Boolean = False 'Allows us to stop the process thread cleanly
              Private WithEvents oWatcher As FileSystemWatch er

              'Check the file to make sure we have exclusive access. No point in processing a file we
              'haven't finished copying yet.
              Private Function FileLock(ByVal Filepath As String, ByVal TimeOut As Integer) As Boolean
              Dim StartTime As Date = Now()
              While True
              If (TimeOut > 0) AndAlso (DateDiff(DateI nterval.Second, StartTime, Now) > TimeOut) Then Exit While
              Try
              Dim oStrm As System.IO.FileS tream = System.IO.File. OpenWrite(Filep ath)
              oStrm.Close()
              oStrm.Dispose()
              Return True
              Catch ex As Exception
              End Try
              'Release thread to other threads until the next thread cycle
              Threading.Threa d.Sleep(0)
              End While
              Return False
              End Function

              'Spit out a messages to the console
              Private Sub WriteEntryToLog (ByVal Entry As String)
              Console.WriteLi ne(Entry)
              End Sub

              'This is the method that verifies the file copy was successful. If it wasn't, it deletes
              'the copy and requeues it. You should add a mechanism in here so that the file isn't requeued
              'if it fails more than a certain amount of times.
              Private Sub VerifyThread(By Val Args As Object)
              Dim oVO As BinaryCopyObjec t = DirectCast(Args , BinaryCopyObjec t)
              If Not oVO.IsMatch() Then
              WriteEntryToLog (String.Format( "{0} copy wasn't successful. Deleting and retrying.", oVO.File1))
              System.IO.File. Delete(oVO.File 2) 'Delete the copy
              AddFileToProces sQueue(oVO.File 1) 'Requeue the original
              Else
              WriteEntryToLog (String.Format( "{0} copied and verified successfully.", oVO.File2))
              End If
              End Sub

              'Thread to process files
              Private Sub ProcessThread(B yVal Args As Object)
              While True
              'Tell our thread to wait here until flagged to process
              ContinueProcess .WaitOne()
              Dim CurrentFile As String = ProcessQueue.Pe ek
              'Send the data to the verification thread
              Dim oVO As New BinaryCompareOb ject
              Dim oFileInfo As New FileInfo(Curren tFile)
              oVO.File1 = InputDirectory & "\" & oFileInfo.Name
              oVO.File2 = OutputDirectory & "\" & oFileInfo.Name
              'Copy file
              System.IO.File. Copy(oVO.File1, oVO.File2)
              'Spin off thread to verify copy
              Dim oVerify As New Thread(AddressO f VerifyThread)
              oVerify.Start(o VO)
              SyncLock ProcessQueue
              ProcessQueue.De queue()
              If ProcessQueue.Co unt = 0 Then
              'Process queue has been emptied, so tell this
              'thread to wait on the next cycle until there
              'are more files to process. There's no point
              'in spinning our wheels.
              ContinueProcess .Reset()
              End If
              End SyncLock
              If StopProcessingF lag Then Exit While
              End While
              End Sub

              'Adds new and changed files to the process queue for processing
              Private Sub AddFileToProces sQueue(ByVal FilePath As String)
              'Don't bother trying to add the file to the process
              'queue until we can get an exclusive lock. If you do
              'you'll find your application failing because the file
              'is locked until editing is complete.
              Dim Timeout As Integer = 20
              If FileLock(FilePa th, Timeout) Then
              'Don't lock the queue any longer than necessary, or
              'you'll hinder performance of your application
              SyncLock ProcessQueue
              If Not ProcessQueue.Co ntains(FilePath ) Then
              ProcessQueue.En queue(FilePath)
              ContinueProcess .Set()
              End If
              End SyncLock
              Else
              WriteEntryToLog (String.Format( "Unable to gain exclusive lock on {0} for {1} seconds. Copy failed", FilePath, Timeout))
              End If
              End Sub

              'This is the event that is fired by our FileSystemWatch er object
              Private Sub FileSystemEvent (ByVal Sender As Object, ByVal e As FileSystemEvent Args)
              AddFileToProces sQueue(e.FullPa th)
              End Sub

              Sub Main()
              'Set up our process thread so that it's ready to run when our watcher starts
              Dim oProcessThread As New Thread(AddressO f ProcessThread)
              oProcessThread. Start()
              'Set up the file watcher to monitor our input directory. Add handlers so that
              'when a file is changed or added, it will trigger our FileSystemEvent handler.
              oWatcher = New System.IO.FileS ystemWatcher(In putDirectory)
              AddHandler oWatcher.Change d, AddressOf FileSystemEvent
              AddHandler oWatcher.Create d, AddressOf FileSystemEvent
              oWatcher.Enable RaisingEvents = True
              'Hold our console window open so we can view the log.
              Console.ReadLin e()
              End Sub
              End Module[/Code]
              Attached Files

              Comment

              • wolfenstein
                New Member
                • Mar 2008
                • 25

                #8
                Thanks you so much balabaster;

                This code sample is really helpful for my requirement, and also helped me to optimise my existing code as well :)

                Continuing this, im little bit confused about the locking states, as my process would need mainly 2 threads; on for writing in the queue when file is created and the second one will read the queue and copy to the destination.

                Now i want that the Thread or FileWatcher should write the queue the moment its created and don't have to wait for any lock to be released as i think in this case it would missed out some files while waiting. It should be Asynchronous?

                About the Reader or Copier; then that should read only when a file is copied completely. (You have used SyncLock for both Writing and Reading)

                Also about the FileWatcher Created Event, if i copy a big sized file then it would be raised on the creation of the file or when file is completely copied?

                Pleasssssseeeee eeeeeee Suggest.......

                Comment

                • balabaster
                  Recognized Expert Contributor
                  • Mar 2007
                  • 798

                  #9
                  Originally posted by wolfenstein
                  Continuing this, im little bit confused about the locking states, as my process would need mainly 2 threads; on for writing in the queue when file is created and the second one will read the queue and copy to the destination.
                  Yes, locking is confusing to start with, but it makes more sense after you've used it a few times. Let's pull apart the ProcessThread method to get to grips with what it's doing: Skip down the code until you get to the line SyncLock ProcessQueue.

                  What we are doing here is telling the application that no other threads can write to the queue until we've finished what we are doing in this block. So...the first line dequeues the file we just finished with and we want to now check to see if the queue is empty so we know whether or not to stop our thread. So we check the queue length and it's zero...we know to pause our thread so it's not spinning its wheels and then we come out of the synclock meaning that other threads can now write to the queue again. In the meantime, the AddFileToProces sQueue method tries to write a new file to the queue. When it tries to write to the queue, the queue object tells it that it must wait, so the AddFileToProces sQueue sits and waits until the queue unlocks at which point it carries on with what it was doing in the first place.

                  So what happens when we remove the synclock? Imagine the same scenario again, except we don't lock the queue. We dequeue the file we just finished with and count the items in the queue. There's no items in the queue. Sometime between dequeueing the item, but before we process the next line of code in this thread (which sets our pause state), the other thread writes a file to the queue and sets the continue flag which would normally tell the process thread to continue processing on it's next loop. But now this thread sets the pause state and we restart our loop and pause waiting. So now our thread sits doing nothing until another file is written to the queue, even though there is one sitting waiting already.

                  I haven't checked to be 100% sure of this, but I'm fairly certain (but I've been wrong in the past):
                  Try removing the SyncLock from the queuing process and run the application. The first time the Queueing thread tries to write to the queue while the Processing thread has it locked, your application will crash. Both sides must use the SyncLock in order for it to work correctly. So in order to SyncLock on read, you must also SyncLock on write.

                  Now i want that the Thread or FileWatcher should write the queue the moment its created and don't have to wait for any lock to be released as i think in this case it would missed out some files while waiting. It should be Asynchronous?
                  If you wanted to spin the queueing process off to a new thread instead of having the the synchronous example we had, you could change the parameters of the AddFileToProces sQueue and change the method call slightly:[Code=vb]Private Sub AddFileToProces sQueue(ByVal Args As Object)
                  Dim FilePath As String = CType(Args, String)
                  'Continue with the rest of the code that was previously here...
                  End Sub

                  Private Sub FileSystemEvent (ByVal Sender As Object, ByVal e As FileSystemEvent Args)
                  Dim oQueueThread As New Thread(AddressO f AddFileToProces sQueue)
                  oQueueThread.St art(e.FullPath)
                  End Sub[/Code]
                  If you do this though, you will definitely have to keep the SyncLock otherwise you're going to end up with many threads all trying to write to the queue while your process thread is trying to clear it and your application will end up with all sorts of deadlock situations.

                  About the Reader or Copier; then that should read only when a file is copied completely. (You have used SyncLock for both Writing and Reading)
                  The file will not be able to be copied until it is finished writing to the file system. The "Changed" and "Created" events occur immediately someone hits save or as the file object is initially created on the file system. So if for example a large file is being copied into your input directory and you immediately try to process it, the process will fail - hence the need for the ExclusiveLock process. You can verify if we could check for an exclusive lock at one of two logical points...either during the course of the process thread or when we queue the file up. In the example I posted, we checked before we queued the file up, but you could queue it up blindly and then verify right before it's copied - which might make more sense depending on the situation. I prefer to check before I queue it as I don't want to have my process thread spinning it's wheels waiting for a file that may waste time waiting to timeout.

                  Also about the FileWatcher Created Event, if i copy a big sized file then it would be raised on the creation of the file or when file is completely copied?
                  It's raised on creation, not once copy is complete. Hence the missing files you've probably noticed....also , when you create a new file, it raises the created event and a bunch of changed events. You will only be able to get an exclusive lock once the final changed event has fired. The only problem is - there is no way to find out how many times the event will fire for any given file. It might fire only once, it might fire 4 times, it may only fire twice. There doesn't seem to be any rhyme or reason for how many times the changed event fires except that it fires at least once for all file changes and creations. You don't really want to queue the same file up many times unecessarily, so the best way I know is to check for an exclusive lock prior to queuing the file up.

                  Comment

                  • wolfenstein
                    New Member
                    • Mar 2008
                    • 25

                    #10
                    Again a lot of thanks for the detailed answer that cleared many issues.
                    Now i'm ok with the Exclusive Lock.

                    Kindly explain this scenario, when a file is created, FileWatcher fired the event and my Process Thread adds it to Queue and also locks the Queue; Now meanwhile another file is created and that will also wait for the lock to be released and so on some new files are also there.

                    Kindly Tell me;

                    1 - All the new files that are created during the Queue is locked by FileWatcher will be queued in the wait state?

                    2 - All these will be separated in threads?

                    3 - Is there any possibility that during this wait time (when a file is already being written in the queue) my process could miss a newly created file?

                    I'm very much concerned about the accuracy and perfection as i need to make sure about each scenario.

                    Again Thank you very much for the detailed examples.

                    Comment

                    • balabaster
                      Recognized Expert Contributor
                      • Mar 2007
                      • 798

                      #11
                      Originally posted by wolfenstein
                      1 - All the new files that are created during the Queue is locked by FileWatcher will be queued in the wait state?
                      Due to the manner in which we are now spinning off a new thread to add items to the queue each time the FileSystemWatch er flags a file, you shouldn't miss any files. The process order is this:
                      • The FileProcess thread is started up and put into a paused state waiting for files to process.
                      • FileSystemWatch er sees a file has been added and/or changed
                      • FileSystemWatch er spins off a new thread that adds the new/changed file to the process queue and immediately goes back to listening for the next file change.
                      • Meanwhile the new queue that was spun off to add the file to the queue now may or may not be in a wait state to add the file to the queue. It may add it immediately, or it may have to wait...but either way, this happens asynchronously to the FileSystemWatch er listening for changes. Once it has added the file to the queue, it updates the processing flag to allow the FileProcess thread to go about processing items in the queue and ends.
                      • The ProcessThread receives the notification to process items in the queue. As it processes each item in the queue it removes them and then spins off another thread to verify the file contents asynchronously while it goes back to process other items in the queue or wait for new items to be added to the queue.
                      So as you see, there is never a point where the FileSystemWatch er is hung up waiting for the ProcessQueue so it can write. Every new/changed file spins off a new thread that does the waiting/writing to the queue, so that it can go back to doing what it does best...hanging out waiting for file changes.
                      Originally posted by wolfenstein
                      2 - All these will be separated in threads?
                      I guess I already answered this one...every new/changed file spins off a new thread. So it's completely asynchronous.
                      Originally posted by wolfenstein
                      3 - Is there any possibility that during this wait time (when a file is already being written in the queue) my process could miss a newly created file?
                      I had the same concern when I originally developed this code for an application for my company, it's been running for the past 9 months without a single hiccup. The ProcessThread in the code for my application is significantly more complex than just copying the file from one directory to another though...

                      Comment

                      • wolfenstein
                        New Member
                        • Mar 2008
                        • 25

                        #12
                        Thanks again, its really making my way clear.

                        According to the Answers now i got some issues while testings;

                        1 - Is this recommended that when my process is copying/Verifying a file, another user tries to open that file. In that case what would be happened?
                        a - He gets the "File in Use Error"
                        b - Should we lock the file during this process instead of before staring it?

                        2 - In your Process Thread; the verifyThread is started after the copy and when it dies?

                        3 - I think when we check the File is completely copied through the Exclusive Lock then we don't need the Changed Event of the File Watcher. Correct?

                        4 - Please give me the syntax of using file watcher in C#, i'm trying it through code instead of form control but the event is not initiated when a file is created.

                        Thanks again and again.

                        Comment

                        • balabaster
                          Recognized Expert Contributor
                          • Mar 2007
                          • 798

                          #13
                          Originally posted by wolfenstein
                          1 - Is this recommended that when my process is copying/Verifying a file, another user tries to open that file. In that case what would be happened?
                          a - He gets the "File in Use Error"
                          b - Should we lock the file during this process instead of before staring it?
                          a). No, because we are only reading the file to calculate an MD5 hash, it doesn't need to get an exclusive lock. However, if someone opens and resaves the file, the new file and the original file will now have different hashes, so the verification will fail in that sense.
                          b). You could open the file exclusively at the start of your verification process to prevent anyone changing the file prior to the verification completion. This would prevent a scenario such as that.

                          Originally posted by wolfenstein
                          2 - In your Process Thread; the verifyThread is started after the copy and when it dies?
                          The verify thread dies once it has finished verifying the file...the process thread continuously loops unless we set the StopProcessing flag to exit that thread.

                          Originally posted by wolfenstein
                          3 - I think when we check the File is completely copied through the Exclusive Lock then we don't need the Changed Event of the File Watcher. Correct?
                          If you don't use the changed flag and a file that already previously exists in your input directory is changed, then it won't be copied. Only newly created files will be copied.

                          Originally posted by wolfenstein
                          4 - Please give me the syntax of using file watcher in C#, i'm trying it through code instead of form control but the event is not initiated when a file is created.
                          [Code=c#]FileSystemWatch er oWatcher = new System.IO.FileS ystemWatcher("N ameOfDirectoryT oWatch", "FilterString") ;[/Code]

                          NameOfDirectory ToWatch is a string value specifying the path of the directory to watch
                          FilterString is an optional string value that tells the FileSystemWatch er what type of files to look for. It works exactly the same as the directory filter when you type "dir" at the command prompt: *.* = all files; *.pdf = all pdf files etc. You can semi-colon delimit this.
                          The IncludeSubDirec tories property of the FileSystemWatch er is a boolean value (true/false) that specifies whether or not to watch sub directories of your main directory or not.

                          Comment

                          • wolfenstein
                            New Member
                            • Mar 2008
                            • 25

                            #14
                            I'm Ok with the rest of issues. Actually these files are audio files so the modification is not possible there, one can only listen them. So thats why i was looking for only Created Event.

                            About the FileWatcher in C#, im having problem to initialize it and handled its event but its not working may be im missing something;

                            Heres the Code;

                            Code:
                                class SourceFileWatcher
                                {
                            
                                    private FileSystemWatcher fileWatcher;
                            
                                    public SourceFileWatcher(string sourceDir, string fileFilter)
                                    {
                                        this.fileWatcher = new FileSystemWatcher(sourceDir, fileFilter);
                                        this.fileWatcher.Created += new FileSystemEventHandler(this.fileWatcher_Created);
                                        this.fileWatcher.EnableRaisingEvents = true;
                                    }
                            
                                    public void fileWatcher_Created(Object sender, FileSystemEventArgs e)
                                    {
                                        Console.WriteLine("File is Created:");        
                                    }
                                }
                            
                            
                            
                                class Program
                                {
                            
                                    static void Main()
                                    {
                                            Program prg = new Program();
                            
                                            SourceFileWatcher sf = new SourceFileWatcher(InputDir, filter);
                            
                                            Console.ReadLine();
                                     }
                            Now when the file is created on the source path then the event is not generated. Kindly let me know what i am missing here.
                            Thanks a lot.

                            Comment

                            • balabaster
                              Recognized Expert Contributor
                              • Mar 2007
                              • 798

                              #15
                              Here's the C# code which does exactly the same but in some areas (particularly the date comparison in the FileLock method) slightly differently. I've also attached the CS file - just like the VB file before, just remove the .txt extension to use it as a module in your code:[Code=c]using System;
                              using System.Security .Cryptography;
                              using System.Text;
                              using System.IO;
                              using System.Threadin g;
                              using System.Collecti ons.Generic;
                              namespace FileCopierClass
                              {
                              class BinaryCopyObjec t
                              {
                              private string _File1;
                              private string _File2;
                              #region Properties
                              public string File1 {
                              get
                              {
                              return _File1;
                              }
                              set
                              {
                              _File1 = value;
                              }
                              }
                              public string File2 {
                              get
                              {
                              return _File2;
                              }
                              set
                              {
                              _File2 = value;
                              }
                              }
                              #endregion
                              #region Methods
                              public static bool Compare(string File1, string File2)
                              {
                              MD5CryptoServic eProvider md5 = new MD5CryptoServic eProvider();
                              md5.ComputeHash (File.ReadAllBy tes(File1));
                              Byte[] hash1 = md5.Hash;
                              md5.ComputeHash (File.ReadAllBy tes(File2));
                              Byte[] hash2 = md5.Hash;
                              return (Convert.ToBase 64String(hash1) == Convert.ToBase6 4String(hash2)) ;
                              }
                              public bool IsMatch()
                              {
                              return Compare(_File1, _File2);
                              }
                              #endregion
                              }
                              class Program
                              {
                              private static string InputDirectory = "C:\\AppTesting \\Input";
                              private static string OutputDirectory = "C:\\AppTesting \\Output";
                              private static ManualResetEven t ContinueProcess = new ManualResetEven t(false);
                              private static Queue<string> ProcessQueue = new Queue<string>() ;
                              private static FileSystemWatch er oWatcher = new FileSystemWatch er();
                              private static bool StopProcessingF lag = false;
                              private static void WriteEntryToLog (string LogEntry)
                              {
                              Console.WriteLi ne(LogEntry);
                              }
                              private static bool FileLock(string FilePath, int TimeOut)
                              {
                              DateTime StartTime = DateTime.Now;
                              while (true)
                              {
                              TimeSpan ts = DateTime.Now - StartTime;
                              if ((TimeOut > 0) && (ts.Seconds > TimeOut)) { break; }
                              try
                              {
                              FileStream oStrm = File.OpenWrite( FilePath);
                              oStrm.Close();
                              oStrm.Dispose() ;
                              return true;
                              }
                              catch { }
                              Thread.Sleep(0) ;
                              }
                              return false;
                              }
                              static void VerifyThread(ob ject args)
                              {
                              BinaryCopyObjec t oVO = (BinaryCopyObje ct)args;
                              if (!oVO.IsMatch() )
                              {
                              WriteEntryToLog (string.Format( "{0} copy wasn't successful. Deleting and retrying.", oVO.File1));
                              File.Delete(oVO .File2);
                              AddFileToProces sQueue(oVO.File 1);
                              }
                              else
                              {
                              WriteEntryToLog (string.Format( "{0} copied and verified successfully.", oVO.File2));
                              }
                              }
                              static void ProcessThread()
                              {
                              ContinueProcess .WaitOne();
                              string CurrentFile = ProcessQueue.Pe ek();
                              BinaryCopyObjec t oVO = new BinaryCopyObjec t();
                              FileInfo oFileInfo = new FileInfo(Curren tFile);
                              oVO.File1 = InputDirectory + "\\" + oFileInfo.Name;
                              oVO.File2 = OutputDirectory + "\\" + oFileInfo.Name;

                              File.Copy(oVO.F ile1, oVO.File2);
                              Thread oVerify = new Thread(VerifyTh read);

                              oVerify.Start(o VO);
                              lock (ProcessQueue)
                              {
                              ProcessQueue.De queue();
                              if (ProcessQueue.C ount == 0)
                              {
                              ContinueProcess .Reset();
                              }
                              }
                              if (StopProcessing Flag)
                              {
                              return;
                              }
                              }
                              private static void AddFileToProces sQueue(string FilePath)
                              {
                              int TimeOut = 20;
                              if (FileLock(FileP ath, TimeOut))
                              {
                              lock (ProcessQueue)
                              {
                              if (!ProcessQueue. Contains(FilePa th))
                              {
                              ProcessQueue.En queue(FilePath) ;
                              ContinueProcess .Set();
                              }
                              }
                              }
                              else
                              {
                              WriteEntryToLog (string.Format( "Unable to gain exclusive lock on {0} for {1} seconds. Copy failed", FilePath, TimeOut));
                              }
                              }
                              private static void FileSystemEvent (object sender, FileSystemEvent Args e)
                              {
                              AddFileToProces sQueue(e.FullPa th);
                              }
                              static void Main(string[] args)
                              {
                              Thread oProcessThread = new Thread(new ThreadStart(Pro cessThread));
                              oProcessThread. Start();
                              FileSystemWatch er oWatcher = new FileSystemWatch er(InputDirecto ry);
                              oWatcher.Change d += new FileSystemEvent Handler(FileSys temEvent);
                              oWatcher.Create d += new FileSystemEvent Handler(FileSys temEvent);
                              oWatcher.Enable RaisingEvents = true;
                              Console.ReadLin e();
                              }
                              }
                              }[/Code]
                              Don't forget that when you're accessing class level variables and other methods from methods defined as static, that the objects they are referencing must also be declared as static...
                              Attached Files

                              Comment

                              Working...