Use a FileSystemWatcher to build a spooler in C#

[FileSystemWatcher]

This example uses a FileSystemWatcher to implement a spooling program.

SPOOL is an ancient computer acronym dating from the 1950s that stands for “Simultaneous Peripheral Operations On-Line.” It is a technique in which jobs are placed in a queue in memory or on disk for later processing.

The most common spooling application is a print queue. Printer jobs are dropped into a spooling directory and the printer prints then when it has a chance.

One of my clients uses several spooling directories to process images. For example, raw images are dumped into one directory. When a process detects a file in that directory, it makes several thumbnails at different sizes for the file and moves the original file into a new “finished” directory. (Depending on the application, you might prefer to delete the files. For example, a print spooler deletes the print jobs after printing them.)

This program uses a FileSystemWatcher to detect new files in a directory. When it detects a file, it moves that file into a different directory. If the destination is occupied by a file with the same name, the program deletes the older file before moving in the new file.

The following list describes the FileSystemWatcher component’s most useful properties.

  • Path – The directory that you want the watcher to monitor.
  • IncludeSubdirectories – Set this to true if you want the watcher to monitor the directory’s subdirectories.
  • Filter – This is a pattern that indicates the kinds of files to monitor. For example, set this to *.txt to monitor text files.
  • NotifyFilter – This tells the watcher what changes to monitor. This can be a combination of FileName, DirectoryName, Attributes, Size, LastWrite, LastAccess, CreationTime, and Security.
  • EnableRaisingEvents – This tells the watcher to raise events when it detects changes. It’s basically this component’s version of an Enabled property. Set this property to true when you want to turn the watcher on. (Set this to true after you set other properties so it doesn’t try to watch for changes that don’t interest you. Setting this last also prevents the component from trying to watch with an invalid Path value–by default Path starts blank.)

When the watcher detects a change to a file. It raises an event to tell you. The events it can raise are Changed, Created, Deleted, and Renamed.

When you click this example’s Watch button, the following event handler executes.

// The input and output directories.
private string InputDir, OutputDir;

// Start the FileSystemWatcher.
private void btnWatch_Click(object sender, EventArgs e)
{
    // Clear the list of files moved.
    lstFilesMoved.Items.Clear();
    lstFilesMoved.Items.Add("Ready");

    // Make sure the file paths end with \.
    InputDir = txtInputDir.Text;
    if (!InputDir.EndsWith("\\")) InputDir += "\\";
    OutputDir = txtOutputDir.Text;
    if (!OutputDir.EndsWith("\\")) OutputDir += "\\";

    // Prepare and start the watcher.
    fswInputDir.Path = txtInputDir.Text;
    fswInputDir.EnableRaisingEvents = true;
}

This code clears the status ListBox and gets the input and output directories. (The example initially uses directories with relative names InputDir and OutputDir. You’ll find them in the executable’s directory.)

Next, the program sets the watcher’s Path and sets EnableRaisingEvents to true.

If a file appears in the input directory (copy, move, or create a file there), the following event handler executes.

// The watcher detected a new file.
// Move it into the output directory.
private void fswInputDir_Created(object sender,
    FileSystemEventArgs e)
{
    // Try to move the file.
    lstFilesMoved.Items.Add(e.Name);
    try
    {
        // Compose the source and destination file names.
        string from_file = InputDir + e.Name;
        string to_file = OutputDir + e.Name;

        // If the destination file already exists, delete it.
        if (File.Exists(to_file)) File.Delete(to_file);

        // Move the file.
        File.Move(from_file, to_file);
    }
    catch (Exception ex)
    {
        lstFilesMoved.Items.Add("    " + ex.Message);
    }
}

This code adds the file’s name to the ListBox. It builds the names of the input and output files. (Alternatively, you could get the input file’s fully qualified path from the e.FullPath parameter.)

Next, the code uses File.Exists to see if the destination file exists. If it does, the program deletes that file.

The code then moves the input file to its new destination. (That won’t work if the destination file already exists.)

The whole things is enclosed in a try-catch block because the new file might be locked by another program. To see an example, use Word to create a new file in the input directory and keep the file open in Word.

If this program cannot move the input file, it just displays a message and gives up. A more robust program might make note of the file and try again later.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in controls, files and tagged , , , , , , , , , , , , . Bookmark the permalink.

2 Responses to Use a FileSystemWatcher to build a spooler in C#

  1. Ziz says:

    I have struggled with Filewatchers in C# in a project I did. The problem is that it double triggers, this is well documented on the web. There are many different solutions but most did not work for me.

    Eventually I found a project called “double_trigger_fix.IO” on the web and that finally solved the issue. Maybe we could have a future article about the double triggers?

    • RodStephens says:

      I’ve also seen watchers not triggering at all. I don’t know what method Microsoft used to implement these, but it doesn’t seem very reliable. A simple polling system might be more consistent.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.