[C# Helper]
Index Books FAQ Contact About Rod
[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Use a FileSystemWatcher to build a spooler in C#

[Use a FileSystemWatcher to build a spooler in C#]

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 the example to experiment with it and to see additional details.

© 2009-2023 Rocky Mountain Computer Consulting, Inc. All rights reserved.