Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Cool File System Class with Thread Support - Easy To Use

3.05/5 (8 votes)
3 Oct 20054 min read 1   720  
An easy to use file system class supporting threads.

Sample Image

Introduction

FileSystem is a class which will enable you to quickly, easily and efficiently get the content of a given directory. A file system class is an essential part of any code library. Every application does some sort of file interaction, and if you create a nice class to handle interaction between your application and the file system then it will make life a bit easier and you will not need to recreate the wheel a hundred times for each project. Here I will try to provide such a class that you can use in your project. This article is an extension of another article (Automating MS Excel 2003 using Visual Studio .NET), which are both part of the same project. However, I have done some modifications to the code provided here that will make it more generic.

So there are two section to this article, one which will cover the FileSystem class and the other that will cover the application that will use the class to demonstrate some of its features.

Background

No background needed, just be familiar with the C# language, threads, and FileSystemObject.

Using the code

Here I will try to cover the FileSystem class. This class is really simple and self explanatory. It is also well documented. But let's go over it in any case. So we have a class named FileSystem that is used to do some file system operations. Let's take a look at the class:

FileSystem Class

Alright, so we have several files that are used internally by the class. Six of them are available as properties that can be accessed at runtime and a few are set during initialization, i.e., sourcePath and destinationPath.

  • COPY_STATUS - is used to notify the parent thread about the status of the copy thread.
  • FILE_FILTER - is used for filtering file types. i.e., *.xml, *.cs, *.xls, etc... if left null it will behave as *.*
  • NUMBER_OF_DIRECTORIES - returns number of directories in the search.
  • NUMBER_OF_FIELS - returns number of files in the search.
  • ROOT_PATH - gets or sets the root path to be used for navigation.
  • STATUS - is the status of the main thread in the FileSystem class.

You also can notice that there are three private methods that are used internally by the class. Two of those methods are used to start a particular thread. And the RecursiveDirectoryNavigation() method is used by the main thread of the FileSystem class to do the navigation, given the rootPath.

To use the copy method of the class you will use one of the two overloaded functions for the constructor and then will call the copyDirectory method which will initiate the startCopyThread to perform the operation. From your main thread you can use the COPY_STATUS property to check on the thread for your next program logic if any.

To use the code, all you need is the following:

C#
CoolFileSystem.FileSystem fileSystem 
               = FileSystem(@root);

That's all it takes! Below you will find code snippets. Of course the full source is available for you to download. Below you can see a portion of the class source.

C#
namespace CoolFileSystem
{
    public class FileSystem
    {
        // Used to hold root directory. Start point for the search.
        private string rootPath;

        ...

        // Used to filter filename when doing
        // the search. By default it is set to "*.xls".
        // Can be changed using the FILE_FILTER property.
        private string fileFilter = "*.*";

        // File list is used internally. It is a list
        // of all files found given the search
        // criteria. Automatically adjust itself. Default size 500.
        private ArrayList fileList = new ArrayList(500);
        
        // Used to store directories found under
        // the rootPath. It contains objects of type
        // DirectoryStructure which hold
        // the Directory Information with a list of files
        // under the current directory.
        private ArrayList directoryList = new ArrayList(500);

        // Used for navigation thru the directory structure.
        private Thread mainThread;
        ...
        
        ...
        public FileSystem(string path)
        {
            rootPath = path;
            mainThread = new Thread(new ThreadStart(startThread));
            mainThread.Start();
        }

        private void startThread()
        {
            DirectoryInfo di = new DirectoryInfo(rootPath);
            RecursiveDirectoryNavigation( di );
        }
        ...
        
        ...
        #region RECURSIVE DIRECTORY NAVIGATION
        [STAThread]
        private void RecursiveDirectoryNavigation( DirectoryInfo di )
        {
            try
            {
                // Add the current directory to the directory list
                DirectoryStructure ds = new DirectoryStructure();
                ds.di = di;

                int insertionIndex = 0;
                // Let's get files in directory
                foreach( FileInfo fi in di.GetFiles(fileFilter) )
                {
                    fileList.Insert(insertionIndex, fi);
                    ds.fileList.Insert(insertionIndex, fi);
                }
                directoryList.Add(ds);
                
                foreach( DirectoryInfo d in di.GetDirectories() )
                {
                    RecursiveDirectoryNavigation( d );
                }
            }
            catch {}
            finally {}
        }
        #endregion

        public ArrayList GetFiles()
        {
            return fileList;
        }

        public ArrayList GetDirectories()
        {
            return directoryList;
        }

        public string GetNumOfFilesCopied()
        {
            return copyNumofFiles.ToString();
        }
    }
    ...

So from above code, you get a preview of the class. The code is well documented so I will not get into the details.

In the following section, I will show you how the class is used in the main code or the driver. In this case, I created a Windows application which has a button, and some labels that show the status of the class. When the button is clicked, you get the FolderBrowseDialog which allows you to select a root; once you select a valid root you will get the results.

DriverCoolFileSystem Class

Okay, so the driver class is used to demonstrate some of the functionality of the FileSystem class. The methods that you should be looking into are the following:

  • butRootDirectory_Click - this function lets the user select the root directory for navigation.
  • timer_Tick - is used by the driver to check on the FileSystem class.
  • ListDirectories - is used to populate the tree view.

When you run the program, and click the Select Root Directory, you get a dialog which will allow you to browse the directory structure. When you make a selection, a FileSystem object is created and the full path is sent within the constructor. A timer is started which checks the status of the FileSystem object. Next step is to update the UI.

C#
namespace CoolFileSystem
{
    /// <summary>
    /// Driver for CoolFileSystem
    /// </summary>
    public class DriverCoolFileSystem : System.Windows.Forms.Form
    {

        // Declare variable for CoolFileSystem
        private CoolFileSystem.FileSystem fileSystem = null;

        ...

        public DriverCoolFileSystem()
        {
            InitializeComponent();
        }
        
        ...
        
        private void butRootDirectory_Click(object sender, System.EventArgs e)
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            DialogResult result = folderBrowserDialog.ShowDialog();
            if( result == DialogResult.OK )
            {
                if( this.fileSystem == null )
                {
                    this.fileSystem = 
                      new FileSystem(@folderBrowserDialog.SelectedPath);
                    timer.Start();
                }
                else
                {
                    MessageBox.Show( "File Sys running ...");
                }
            }
        }

        private void timer_Tick(object sender, System.EventArgs e)
        {
            this.lblDirectories.Text = "Num of Directories: " + 
                         this.fileSystem.NUMBER_OF_DIRECTORIES;
            this.lblFiles.Text = "Num of Files: " + 
                         this.fileSystem.NUMBER_OF_FILES;
            this.lblStatus.Text = "Status: " + this.fileSystem.STATUS;
            if( this.fileSystem.STATUS.Equals("Stopped") )
            {
                this.lblStatus.Text = "Status: " + this.fileSystem.STATUS;
                timer.Stop();

                // populate the tree view
                Thread listFolders = 
                   new Thread(new ThreadStart(ListDirectories));
                treeView.Nodes.Clear();
                listFolders.Start();
            }
        }

        private void ListDirectories()
        {
            ArrayList directoryList = this.fileSystem.GetDirectories();

            foreach( DirectoryStructure ds in directoryList )
            {
                if( ds.fileList.Count > 0 )
                {
                    TreeNode folder = new TreeNode(ds.di.Name.ToString());

                    foreach( FileInfo fi in ds.fileList )
                    {
                        TreeNode file = new TreeNode(fi.FullName);
                        folder.Nodes.Add(file);
                    }

                    // Vahe Karamian - 03/01/2005 - This is for Thread Safety
                    if(treeView.InvokeRequired == true)
                    {
                        // check if we running within the same thread
                        treeView.Invoke(new AddToTreeView(treeView.Nodes.Add), 
                            new object[] {folder});
                    }
                    else
                    {
                        treeView.Nodes.Add(folder);
                    }
                }
            }
            this.fileSystem = null;
        }

    }
}

If you notice, there is a timer which is set to check the status of the file system thread every second. Again, the code is simple and I will not get into the details. I hope that this code sample gives yet a different approach to doing file system navigation.

Points of Interest

The class is very flexible and you can easily extend it and use it in your own programs. One of the features which I removed from the current release for CodeProject is the ability to search for the same type of files and get the latest one for processing. There are some minor adjustments you will need to do in order to get the functionality. What I provided here is a general code base that can be used by everyone.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here