Click here to Skip to main content
Click here to Skip to main content

Directory Mirror using the FileSystemWatcher class

By , 31 Mar 2013
 

About

The Directory Mirror is an experimental application that uses and extends the Microsoft .NET framework FileSystemWatcher class. It monitors the files and sub-folders of a specified source directory and maintains a copy of it in another directory. This application can help you learn things about the FileSytemWatcher class and IO file and directory operations.

Things to know about the FileSystemWatcher

The first thing to keep in mind when working with the FileSystemWatcher is that it's not a one for one relationship between the IO actions in the monitored directory and the events raised by the FileSystemWatcher. For an application like this one you will quickly notice that the created event is always followed by at least one changed event. When a file is copied into a monitored directory, it is first created (the header and info is first written) and then the actual data is written. Depending on the file size (and the time it takes to write it, as well as system performance and availability), many changed events may be raised because the file is constantly changing as it is being written (monitored by the LastWrite and/or Size NotifyFilters of the FileSystemWatcher) and this may vary greatly from one system/environment to another.

The internal buffer size is limited to a maximum value of 64KB but for an application like this one isn't not the bottleneck. A big batch operation can send a lot of information to the FileSytemWatcher so fast that it wont be able to keep track, long before the buffer is full; You will get the to many changes at once error. For instance if you select a few hundred files in a monitored directory and then hit delete, it will probably happen. The same thing can happen if you move a large number of files to the monitored directory and those files are located on the same partition as the monitored directory; Being on the same partition, no actual copying really happens, only the address of the files change and this happens very fast.

The solution

The solution contains two projects, one for the forms and the other for the Directory Mirror class and things realted to that class. I won't go through the forms here but just explain what's in the FSWDirectoyMirror project. First there's a folder containing some static IO and XML methods. The controller sits between the forms and the directory mirror objects. There's the DirectoryMirror of course. The DMHolder is used to hold and help keep track of the configuration information of DirectoryMirror objects. Enum contains a few enums of course. FSWabstract is an abstract class based on the FileSystemWatcher class and The DirectoyMirror class is based on this. I could have skipped this and base The DirectoryMirror class directly on the FileSystemWatcher but I often like to use an abstract as a starting point because it reminds me how I thought things at the beginning and helps me keep things organized. MirrorEventArgs is an entity used to carry information from the events raised in the mirror folder. Configurations of the DirectoryMirror objects are written to the mirrors.xml file (if the file is not found the application creates a new one). SourceEventArgs is an entity used to carry information from the events raised in the source folder. The following diagram shows how the application is structured; there is no direct communication between the DirectoryMirror objects and the forms, everything passes through the controller object.

The screens

Main screen

At the top of the form there are 3 buttons, the info button displays info about the application, the add button to create a new configuration and the save button that writes the list of configurations to an XML file. You then have 4 checkboxes for displaying information in the activity tab:

  • View source activity: Reports activity detected in the source directory.
  • View source errors: Reports errors detected in the source directory
  • View mirror activity: Reports activity detected in the mirror directory.
  • View mirror errors: Reports errors detected in the Mirror directory
  These checkbox options can be changed while instances of the DirectoryMirror are running.

Configurations tab 

The configurations tab first shows a list of DirectoryMirrors controls, one for each configuration. The name is displayed in the upper left corner followed by 3 buttons. The tool button opens the edit form to make changes. The recycle bin button deletes the configuration and the third one is the strart/stop button. Next are displayed the timer and buffer values. Under those values are displays the paths to the source directory and mirror directory.

The bottom part of the control offers various options:

  • InfoMode: No mirror directory is used and the application only reports about the activity detected in the source directory.
  • MirrorMode: In reaction to the changes detected in the source directory, the contents of the mirror directory are updated to match.
  • Monitor changed event: Enables or disables the tracking of the FileSystemWatcher's "changed" event.

Activity tab

The first grid shows the activity in the monitored directory and the second one is the mirror directory. Another way of saying it would be that the first grids shows the FileSystemWatcher's native events and the second grid pertains to the events we've added to the FileSystemWatcher to make it a DirectoryMirror.

Edit screen

The timer indicates how much time to wait before updating the mirror folder.

The buffer is the internal buffer size of the FileSystemWatcher object. It stores information about the detected events and the files and directories they pertain to. The buffer can overflow if it has more information that it can handle. The buffer comes from non-paged memory and can not be swapped out to disk.

The name textbox let's you set a friendly name to identify the configuration. The source and mirror textboxes and buttons are for selecting or typing these paths. For a remote computer you must use UNC paths (i.e.,: \\remoteComputer\targetFolder), mapped drives and removable USB storage will not work.

All fields are required and a validation is performed before you can confirm changes and return to the list of configurations. There is also a validation to ensure that the mirror directory isn't contained in the source directory and vice versa this would start a catastrophic reaction. However if you are running multiple DirectoryMirrors there is no validation of that sort between the running DirectoryMirrors; you could start an instance that has folder A as the source and folder B as the mirror and another one with folder B as the source and folder A as the mirror. You don't want to do that so use caution when running multiple instances.

Rebuild dialog

In order for this application to work, the contents of the source and mirror folders must be identical when the application starts. When starting an instance of the DirectoryMirror you have three options to rebuild the mirror:

  • Hard rebuild deletes the contents of the mirror and copies the contents of the source into it.
  • Comparative rebuild compares the contents of the two folders by file name and size and makes the appropriate changes ( a good option if you don't have a lot of files but some very big ones).
  • Delete all deletes the contents of both folders.

How it works 

Every time an events is fired in the source folder, the timer is reset and information about the event is sent to a queue. When the timer expires, the events from the queue are copied to a list, the contents of the queue are cleared and the process of updating the mirror folder begins, using the newly created list. This way new events can be sent to the queue while the mirror is being updated. The timer does not guaranty that there is no more activity in the source folder when it's time to update the mirror but it diminishes that possibility. If you can anticipate what kind of file activity you will get you can adjust the timer value accordingly.

You’ll notice there is a checkbox to let you monitor or not the changed event. Because it only occurs after a created event, it is not necessary to monitor it for this application. The application works pretty good but if you have some intense file activity (big batch operations involving hundreds of files and/or some very large files).  As mentioned earlier the firing of events by the FileSystemWatcher can differ depending on the system/environment. Try with and without the changed event and using a bigger timer value.

The code

The FSWabstract abstract class

using System;
using System.IO;

namespace DM
{
    // This class is based on the FileSystemWatcher class
    public abstract class FSWabstract : FileSystemWatcher
    {
        // Delegates and events to send messages about FileSystemWatcher events
        public delegate void SourceEventDelegate(SourceEventArgs fswEventArgs);
        public event SourceEventDelegate SourceEvent;
        public delegate void SourceErrorDelegate(SourceEventArgs fswEventArgs);
        public event SourceErrorDelegate SourceError;

        public string FriendlyName { get; set; }

        protected FSWabstract()
        {
            // Changed, Created and Deleted event handlers have common parameters "object"
            // and "FileSystemEventArgs" so we'll use the same delegate for those 3
            Changed += FSWcontract_IoActivity;
            Created += FSWcontract_IoActivity;
            Deleted += FSWcontract_IoActivity;
            Renamed += FSWcontract_Renamed;
            Error += FSWcontract_Error;
        }

        // Enable or disable tracking of "Changed" event.
        public void TrackChangedEvent(bool value)
        {
            if (value) Changed += FSWcontract_IoActivity;
            else Changed -= FSWcontract_IoActivity;
        }

        // Tracks FilsSystemWatcher Errors
        private void FSWcontract_Error(object sender, ErrorEventArgs e)
        {
            SourceEventArgs fswe = new SourceEventArgs();
            fswe.FSWname = this.FriendlyName;
            fswe.TimeStamp = DateTime.Now;
            fswe.Path = e.GetException().Message;
            fswe.EventType = "Error";
            SourceError(fswe);
        }

        // Tracks FilsSystemWatcher "Renamed" events
        private void FSWcontract_Renamed(object sender, RenamedEventArgs e)
        {
            SourceEventArgs fswe = new SourceEventArgs();
            fswe.FSWname = this.FriendlyName;
            fswe.TimeStamp = DateTime.Now;
            fswe.OldPath = e.OldFullPath;
            fswe.Path = e.FullPath;
            fswe.EventType = e.ChangeType.ToString();
            SourceEvent(fswe);
        }

        // Tracks FilsSystemWatcher "Changed", Created" and "Deleted" events
        private void FSWcontract_IoActivity(object sender, FileSystemEventArgs e)
        {
            SourceEventArgs fswe = new SourceEventArgs();
            fswe.FSWname = this.FriendlyName;
            fswe.TimeStamp = DateTime.Now;
            fswe.Path = e.FullPath;
            fswe.EventType = e.ChangeType.ToString();
            SourceEvent(fswe);
        }
    }
}

The DirectoryMirror class

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Timers;
using DM.StaticMethods;

namespace DM
{

    // This class is based on the FSWabstract abstract class
    public class DirectoryMirror : FSWabstract
    {
        string _mirDir = ""; // Path of the mirror directory
        List<sourceeventargs> _IOlist; // List to keep track of chages in the source diretory
        double _time;
        Timer _timer;
        bool _mirrorMode;

        public string SourceDirectory
        {
            get { return this.Path; }
            set { this.Path = value; }
        }

        public string MirrorDirectory
        {
            get { return _mirDir; }
            set { _mirDir = value; }
        }

        public double Milliseconds
        {
            get { return _time; }
            set { _time = value; }
        }
        public bool MirrorMode
        {
            get { return _mirrorMode; }
            set { _mirrorMode = value; }
        }        

        //Delegates and events to send messages about Exceptions
        public delegate void MirrorActionDelegate(MirrorEventArgs info);
        public event MirrorActionDelegate DMinfoEvent;
        public delegate void MirrorErrorDelegate(MirrorEventArgs info);
        public event MirrorErrorDelegate DMerrorEvent;

        public DirectoryMirror()
        {
        }

        public DirectoryMirror(string name, string srcDir, string mirDir)
        {
            this.FriendlyName = name;
            _IOlist = new List<sourceeventargs>();
            // Set up the path to the source directory
            SourceDirectory = srcDir;
            // Set up the path to the mirror directory
            MirrorDirectory = mirDir;
            //Start();
        }

        public void Start()
        {
            if (!string.IsNullOrEmpty(SourceDirectory) &&
                !string.IsNullOrEmpty(MirrorDirectory))
            {
                // Set up the different properties
                // Monitor all files and directories
                Filter = "";
                // Listen for changes in the name of files and directories
                // and changes in size
                NotifyFilter = (NotifyFilters.FileName |
                    NotifyFilters.DirectoryName | NotifyFilters.LastWrite);
                IncludeSubdirectories = true;
                EnableRaisingEvents = true;


                if (_mirrorMode)
                {
                    SourceEvent += DirectoryMirror_FSWevent;
                    SourceError += DirectoryMirror_FSWerror;
                    _timer = new Timer();
                    _timer.Elapsed += timer_Elapsed;
                    _timer.Interval = _time;
                    _timer.AutoReset = false;
                    _IOlist = new List<sourceeventargs>();
                }
            }
        }

        void DirectoryMirror_FSWerror(SourceEventArgs fswEventArgs) 
        {
            _timer.Start();
        }

        void DirectoryMirror_FSWevent(SourceEventArgs fswEventArgs) 
        {          
            _timer.Start();
            _IOlist.Add(fswEventArgs);
        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            MirrorEventArgs args = new MirrorEventArgs();
            args.FSWname = this.FriendlyName;
            args.TimeStamp = DateTime.Now;
            args.Info = "Timer elapsed";
            DMinfoEvent(args);
            if (_IOlist.Count > 0)
            {
                List<sourceeventargs> list = new List<sourceeventargs>();
                lock (_IOlist)
                {
                    list.AddRange(_IOlist);
                    _IOlist.Clear();
                }

                updateMirror(list);
            }
        }

        private void updateMirror(List<sourceeventargs> list)
        {
            MirrorEventArgs args = new MirrorEventArgs();
            args.FSWname = this.FriendlyName;
            args.TimeStamp = DateTime.Now;
            args.Action = "Begin Mirror Update";
            args.Info = list.Count.ToString() + " event(s) to process";
            DMinfoEvent(args);

            string destination;
            List<sourceeventargs> listF = new List<sourceeventargs>();

            try
            {
                //--- Created ---//
                listF = list.Where(x => x.EventType == "Created").ToList();
                for (int i = 0; i < listF.Count; i++)
                {
                    destination = listF[i].Path.Replace(SourceDirectory, MirrorDirectory);                    
                    if (Directory.Exists(listF[i].Path))
                    {                       
                        Directory.CreateDirectory(destination);
                        IOmethods.CopyDirectoryRecursively(listF[i].Path, destination);
                        list.Remove(listF[i]);
                        // Remove all "Created" and "Changed"
                        // events of child folders and files from the master list
                        list = list.Where(s => (s.EventType == "Created" || 
                          s.EventType == "Changed") && s.Path.Contains(listF[i].Path) == false).ToList();
                        // Update the sublist of "Created events"
                        listF = list.Where(x => x.EventType == "Created").ToList();
                        i -= 1;
                        args = new MirrorEventArgs();
                        args.FSWname = this.FriendlyName;
                        args.Action = "Create";
                        args.TimeStamp = DateTime.Now;
                        args.Info = destination;
                        DMinfoEvent(args);

                    }
                    else
                    {
                        File.Copy(listF[i].Path, destination, true);
                        // Remove all "Changed" events for this file from the master list
                        list = list.Where(s => (s.EventType != "Changed" && s.Path != listF[i].Path)).ToList();
                        // Update the sublist of "Created events"
                        listF = list.Where(x => x.EventType == "Created").ToList();
                        i -= 1;
                        args = new MirrorEventArgs();
                        args.FSWname = this.FriendlyName;
                        args.Action = "Create";
                        args.TimeStamp = DateTime.Now;
                        args.Info = destination;
                        DMinfoEvent(args);
                    }
                }
            }
            catch (Exception x)
            {
                args = new MirrorEventArgs();
                args.FSWname = this.FriendlyName;
                args.TimeStamp = DateTime.Now;
                args.Action = "Error";
                args.Info = x.Message;
                DMerrorEvent(args);
            }
            try
            {
                //--- Changed ---//
                listF = list.Where(z => z.EventType == "Changed").ToList();
                listF = RemoveDuplicates(listF);
                foreach (SourceEventArgs f in listF)
                {
                    if (File.Exists(f.Path))
                    {
                        destination = f.Path.Replace(SourceDirectory, MirrorDirectory);
                        File.Copy(f.Path, destination, true);
                        args = new MirrorEventArgs();
                        args.FSWname = this.FriendlyName;
                        args.Action = "Copy";
                        args.TimeStamp = DateTime.Now;
                        args.Info = destination;
                        DMinfoEvent(args);
                    }

                }
            }
            catch (Exception x)
            {
                args = new MirrorEventArgs();
                args.FSWname = this.FriendlyName;
                args.TimeStamp = DateTime.Now;
                args.Action = "Error";
                args.Info = x.Message;
                DMerrorEvent(args);
            }
            try
            {
                //--- Renamed ---//
                listF = list.Where(x => x.EventType == "Renamed").ToList();
                foreach (SourceEventArgs f in listF)
                {
                    destination = f.Path.Replace(SourceDirectory, MirrorDirectory);
                    if (System.IO.Directory.Exists(f.OldPath.Replace(SourceDirectory, MirrorDirectory)))
                    {
                        string oldFPath = f.OldPath.Replace(SourceDirectory, MirrorDirectory);
                        string newFPath = f.Path.Replace(SourceDirectory, MirrorDirectory);
                        System.IO.Directory.Move(oldFPath, newFPath);
                    }
                    else
                    {
                        string oldFPath = f.OldPath.Replace(SourceDirectory, MirrorDirectory);
                        string newFPath = f.Path.Replace(SourceDirectory, MirrorDirectory);
                        System.IO.File.Move(oldFPath, newFPath);
                    }
                    args = new MirrorEventArgs();
                    args.FSWname = this.FriendlyName;
                    args.Action = "Rename";
                    args.TimeStamp = DateTime.Now;
                    args.Info = destination;
                    DMinfoEvent(args);
                }
            }
            catch (Exception x)
            {
                args = new MirrorEventArgs();
                args.FSWname = this.FriendlyName;
                args.TimeStamp = DateTime.Now;
                args.Action = "Error";
                args.Info = x.Message;
                DMerrorEvent(args);
            }
            try
            {
                //--- Deleted ---//
                listF = list.Where(x => x.EventType == "Deleted").ToList();
                foreach (SourceEventArgs f in listF)
                {
                    destination = f.Path.Replace(SourceDirectory, MirrorDirectory);
                    if (Directory.Exists(destination))
                    {
                        Directory.Delete(destination, true);
                    }
                    else
                    {
                        File.Delete(destination);
                    }
                    args = new MirrorEventArgs();
                    args.FSWname = this.FriendlyName;
                    args.Action = "Delete";
                    args.TimeStamp = DateTime.Now;
                    args.Info = destination;
                    DMinfoEvent(args);
                }
            }
            catch (Exception x)
            {
                args = new MirrorEventArgs();
                args.FSWname = this.FriendlyName;
                args.TimeStamp = DateTime.Now;
                args.Action = "Error";
                args.Info = x.Message;
                DMerrorEvent(args);
            }
            args = new MirrorEventArgs();
            args.FSWname = this.FriendlyName;
            args.TimeStamp = DateTime.Now;
            args.Action = "End Mirror update";
            DMinfoEvent(args);
        }

        private List<sourceeventargs> RemoveDuplicates(List<sourceeventargs> list)
        {
            list = list.OrderBy(z => z.FSWname).OrderBy(z => z.Path).ToList();
            List<sourceeventargs> newList = new List<sourceeventargs>();
            SourceEventArgs last1 = new SourceEventArgs();
            last1.Path = "+";
            last1.FSWname = "";
            foreach (SourceEventArgs fswa in list)
            {
                if (fswa.FSWname != last1.FSWname || fswa.Path != last1.Path)
                {
                    newList.Add(fswa);
                    last1 = fswa;
                }
            }
            return newList;
        }
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Luc Archambault
Web Developer
Canada Canada
Member
I have been working with different web technologies (ASP, ASP.NET, ColdFusion, Perl/CGI) for the past 15 years. I live in Montreal, where I work for a little consultant group specializing in Microsoft technologies.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionDirectory Mirrormemberdoctorcpu29 Apr '13 - 6:15 
Has this been tested with Windows 8 as it seems to crash after a few minutes of operation. Excellent work by the way. doctorcpu@hotmail.com
 
Providing my email because I'm not sure how this site works.
 
Thanks, Any help is appreciated.
AnswerRe: Directory MirrormemberLuc Archambault1 May '13 - 8:49 
Hi,
No, I've never tried it on windows 8...
QuestionNice work, and two questions, and one suggestionmemberBillWoodruff29 Mar '13 - 3:33 
+5: I look forward to studying your code !
 
You wrote: "FSWabstract is an abstract class based on the FileSystemWatcher class and The DirectoyMirror class is based on this. I could have skipped this and base The DirectoryMirror class directly on the FileSystemWatcher but I often like to use an abstract as a starting point because it reminds me how I thought things at the beginning and helps me keep things organized."
 
I am curious about the advantages of this kind of architecture: how exactly does the creation of an abstract class, and a second class, that inherits from that abstract class, help you "organize things" for this kind of application ?
 
I also wonder, given your original article was in 2005, if, in later versions of the .NET FrameWork, there has been any change in the performance of the FileSystemWatcher class, any improvement in its ability to handle the scenarios where you observed it didn't function with large files, or large numbers of files, being transferred.
 
Finally, it would be good to see, at the end of this article, as is kind of traditional for CP articles, a brief summary of the changes you have introduced in the March 29, update.
 
thanks, Bill
“Beginning, middle, and end of birth, growth, and perfection we behold is from contraries, by contraries, and to contraries; and whatever contrariety is, there is action, reaction, there is motion, diversity, multitude, order.”
Giordano Bruno, cosmologist, philosopher, burned at the stake for heresy on February 17, 1600. When condemned, he said to his Inquisitors: “Perhaps you pronounce this verdict against me with greater fear than I receive it.”

AnswerRe: Nice work, and two questions, and one suggestion [modified]memberLuc Archambault31 Mar '13 - 14:31 
Hi and thanks for the vote.
 
Well the abstract is a customized version of the FileSystemWtcher class. I have to channels for the events; one for the errors and and a second one for the events them selves, and I've created my own event args with the info that I need. Everything that has to do with The functionality of the FSW is in the abstract and the added functionality to make it a DM is in the class that inherits from it.
 
I don't think that there have been any changes at all in the FileSystemWatcher class since .Net 1.0. I could be wrong but if there were any they are very minor.
 
Yeah I could have mentioned the changes but there are so many; I rewrote everything. You can now run multiple instances of the DM, use of a timer for the update process....

modified 7 Apr '13 - 5:02.

GeneralMy vote of 5memberWhiteOsoBDN4 Mar '13 - 5:20 
Very good work!!!
GeneralRe: My vote of 5memberLuc Archambault5 Mar '13 - 16:39 
Thanks!
QuestionVery nice work.memberJipin9 Apr '12 - 20:23 
I am really very impressed by this article. I also want to ask you some questions.
1) What if i dont want to delete the mirror folder and create new one, i just want the same mirror folder to hold the changed files in source folder with time stamps and create different copies of it in the mirror folder. I mean the mirror folder should work as a backup folder for the files in source folders.
2)Can we provide a remote computers path as a destination.
AnswerRe: Very nice work.memberLuc Archambault10 Apr '12 - 10:31 
This goes way back... I've done a new improved version (.net 4.0) and have been wanting to rewrite this article.
 
1) Yes, the code that deletes the folder is in the form, when you launch the mirror...
 
2) Yes, that works. UNC paths(\\myComputer\myFolder) or mapped drive, one of those 2 will work or maybe both, I can't remember.
GeneralRe: Very nice work.memberJipin11 Apr '12 - 7:15 
Have you uploaded the improved version.IF yes please provide me the link.It will be of a great help to me..
GeneralRe: Very nice work.memberLuc Archambault20 Apr '12 - 12:38 
I'm on it, check back here in a week or 2...
Questioncan u provide the document for this projectmemberMember 823648420 Sep '11 - 0:51 
Can u provide the document for this project, kindly pls help. mail me babu_compengg@hotmail.com
AnswerRe: can u provide the document for this projectmemberLuc Archambault20 Sep '11 - 8:11 
There's a link at the begining
QuestionHow to get closing event of other application in my running applicationmemberPatel Pranav23 Apr '10 - 20:32 
we are creating folderWatcher application that keeps track of all coming file in WatchFolder. When we receive new file, we transferred it to specified location. In my case for example, if user create/open existing word document and select SaveAs option to save and Save the file in our watchfolder. at this moment we getting event of Creation and Changed, so we are able to transferred file to specified location. Note that: still user has not closed word application, continue changing and saving file.
 
My question: When user close the word document we want to delete that file from watchfolder because it is no more in use as we have already copy this file in specified folder. How could i know that any other application(like word,excel,notepad,pdf etc..) is going to be close in my application? If so then i can easily delete watchfolder file. I have tried FindWindowLike/GetwindowTitle api but in many application i found that file name are not painted on title.
 
Thanks in advance
Don't Expect A Good Day! Make One...!

AnswerRe: How to get closing event of other application in my running applicationmemberLuc Archambault27 Apr '10 - 12:40 
You shouldn't be able to delete a file if it is in use by an application, you'll get an IO exception. You should try using a timer to try and delete the file after it has been saved, one minute later.
GeneralThanksmemberEdward Ceballos4 Aug '08 - 4:59 
Cool!!! Big Grin | :-D
 
Edward Ceballos

GeneralThank youmembernirvansk8157 Apr '08 - 15:28 
Great work. This will help me further my own project[^]. You get a 5 from me.
 
Mike
GeneralWorks great, but we need a few tweaks.memberlmeyers15 Feb '08 - 17:04 
Luc, I would love to get your help with a few enhancements to this nifty little app. We have a simple asp.net document management system where users maintain project specific files. The app is entirely file based, meaning that no file meta data nor blob data is saved to db. Many users would like to mirror selected web server file directories to their local drive (all sites Win based). Would be very cool if it was bidirectional synch, such that users could edit local files with mods posted back to web server. In the course of posting file changes it would be trivial to post to SQL change log. Lastly we would like to archive file versions when there are changes. I can give you or whomever much more detailed specs. Let me know if this might be fun project for you.
 
Thanks, Lauren
lmeyers@microssoftware dot com
GeneralEvents firing twicememberp10006 Mar '07 - 3:45 
Hi Luc,
 
I just created a short test of the FileWatcher. I just set up the file watcher as follows:
 
watcher = new FileSystemWatcher("C:\\TEMP");
watcher.Filter = "";
watcher.NotifyFilter =((NotifyFilters)(NotifyFilters.LastWrite));
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
 
The watcher_Changed handler just opens a MessageBox telling me that something happened.
 
I then created a text file in C:\TEMP and then I edited it using Notepad. When I saved the changes to the text file, watcher_Changed was called twice in a row. Have you ever encountered this? Is Notepad modifying the file twice? Or is this a bug in FileWatcher?
 
Thanks.
Generalnice work ~!greatmembernicesnow5 Feb '07 - 15:57 
it's a nice work!
im glad to see it .thanks with respect ..
 
looking foward to seeing the bugs fixedSmile | :) and more extension
 
learn more

Questionhow bout web application?member!ndera12 Dec '06 - 16:51 
can it use for mirroring from or to internet?
 
indra kharisma
.. :: every single step are meaning :: ..

AnswerRe: how bout web application?memberLuc Archambault13 Dec '06 - 7:51 
Yes, if you have access to the server's file system it will work just the same. But this is an experimental application; I wouldn't use it into production for anything important.
GeneralMonitor a list of pathmemberpasdan22 May '06 - 22:41 
Hello,
I would like to monitor a list of path that I read from a table. Can I set the path property of the filesystemwatcher to monitor a list of path, or I have to create an istance of the filesystemwatcher class for each path in the table?
 
Thank you
QuestionHow can we solve the IO exception?memberchallengerking19 Apr '06 - 17:06 
Wonderful work! thank you, Luc.
I have a test about this project, when i dropping a folder that contains many files and subfolders, it throw the IO exception like this:"EXCEPTION (onChanged): IO ERROR The process can not access the file '...' because it is used by another process".
The application manages could not to successfully complete! e.g. i dropping 600M files into the "soureFolder", but in the "mirrorFolder" it has only 350M at last.
So, i want to know, how can we solve this problem.
Sincerely please give me a reply, this sample is so practical for me. thanks. Big Grin | :-D
 
love life.
 
-- modified at 23:09 Wednesday 19th April, 2006
AnswerRe: How can we solve the IO exception?memberLuc Archambault19 Apr '06 - 18:45 
Hi,
When I started playing around with the FileSystemWatcher I saw enormous potential and uses for this class but I quickly realized that it had some major flaws; this is why I built this little experimental application, to find out more about the flaws of the FileSystemWatcher class.
 
Here is my hypostasis about the flaws:
When you copy or drop large amounts of data somewhere it can take several seconds for the system to write the data to the disk. The system cannot send feedback about the status of the operation (completed, failed, queued, etc) while it is performing it or while it is queued, and during this time other requests to the file system are queued by the system. This is what I think is the source of the problem: The FileSystemWatcher has no patience and throws an exception if it doesn’t get an EMMEDIATE response from the file system. So any big operation that takes a bit of time will end up throwing an exception and often but not always, cause the operation to abort. This class seems to be completely ignorant of how the windows file system works.
 
This would explain why it usually works well when dealing with small amounts of data but cannot handle large amounts of data and/or large amounts of files.
 
On a first level it can handle small amounts of file and data. On a second level with somewhat larger amounts of data and files an exception is thrown but the operation is still carried out successfully. On a third level with very large amounts of data there is an exception and the operation fails to complete.
 
Personally I can’t see any workaround to this problem, but if anyone can I would love to hear about it.
 

Luc

GeneralRe: How can we solve the IO exception?memberchallengerking19 Apr '06 - 19:32 
Thank you, Luc.
You provided penetrating insight into the FileSystemWatcher class,
Yes your opinion about it is so exact, i agree with you.
The system cannot send feedback about the status of the operation (completed, failed...) while the program is running, so when we copy
a big file (for example, a video file(.avi, .rmvb, .mepg, etc)), the IO exception will be thrown.Cry | :((
May be this is a bug of the FileSystemWatcher class from .NET.;P
 
love life.
 
-- modified at 1:33 Thursday 20th April, 2006

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 31 Mar 2013
Article Copyright 2005 by Luc Archambault
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid