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

File Searcher in C#

4.80/5 (52 votes)
29 Sep 2012CPOL4 min read 160.2K   10.4K  
A freeware file searcher in C#
Image 1

Introduction

On a Windows Vista PC, I tried to search my hard disk for a file that contains a certain string. This was not possible using Windows Explorer. So, I decided to write my own file searcher. And, here it is...

What It Does

You must enter a search directory, so the program knows where to search for files and directories. If you check the "Include subdirectories" checkbox, the program will recursively search in all subdirectories of the search directory. The filename specified can be something like "*.wav;*.mp3;Christma??ree.*". The program will list all files and directories matching these filenames.

You can also use some restrictions to restrict the found items. Each restriction must be activated by checking the appropriate checkbox, and the necessary parameter for this restriction can be entered to the right of the checkbox.

  • "Files newer than" will only list the items that have a LastWriteTime greater than the parameter.
  • "Files older than" will only list the items that have a LastWriteTime less than the parameter.
  • "Files containing the string" will only list the items that contain the string parameter you entered.
  • The program will convert this string parameter into a byte sequence, using either ASCII or Unicode encoding (depending on what you select), and then search each file for an occurrence of this byte sequence.

Click the "Start" button to start the search. The found items will be listed below. If the search takes too much time and you want to cancel it, you can click the "Stop" button to stop the search.

If you double-click an item that represents a file, the program will open this file within the application that is associated with the file's extension.

If you right-click an item and select "Open Containing Folder", the program will open the folder containing the file or directory in Windows Explorer.

If you want to write the search results to a text file, enter a delimeter that shall be used to separate items in the text file, and then click the button "Write results to text file...".

Using the Code

This application consists of two main parts:

  1. The MainWindow class does all the user interface stuff.
  2. The Searcher class provides the business logic for searching FileSystemInfo objects.

When the user clicks the "Start" button, the method Searcher.Start is executed. It starts a new thread called SearchThread. This thread searches for files and directories, matching the parameters that were entered by the user. If it finds a matching FileSystemInfo object, it raises an asynchronous FoundInfo event, so that the MainWindow can extract the FileSystemInfo object from the FoundInfoEventArgs, and update its results list. When the thread ends, it sets the m_thread member to null. The Searcher.Start method checks if m_thread is null every time it is executed, so there can never be more than one thread running at the same time.

When the user clicks the "Stop" button, the method Searcher.Stop is executed. It sets the m_stop member to true, so that the SearchThread can recognize this change and stop itself as soon as possible. Notice that this operation is thread-safe, because a boolean variable needs only one operation step to be set.

Important: In the Searcher_FoundInfo event handler, the MainWindow uses its Invoke method to invoke the this_FoundInfo method through a delegate. This way, the MainWindow makes sure that the code for updating the results list is executed in the MainWindow's thread, and not in the Searcher's thread. Calling the this_FoundInfo method directly would cause the application to crash, because the Searcher_FoundInfo event handler is not synchronized to the GUI controls.

C#
private delegate void FoundInfoSyncHandler(FoundInfoEventArgs e);
private FoundInfoSyncHandler FoundInfo;

...

private void MainWindow_Load(object sender, EventArgs e)
{
    ...
    this.FoundInfo += new FoundInfoSyncHandler(this_FoundInfo);
    ...
}

...

private void Searcher_FoundInfo(FoundInfoEventArgs e)
{
    if (!m_closing)
    {
        this.Invoke(FoundInfo, new object[] { e });
    }
}

private void this_FoundInfo(FoundInfoEventArgs e)
{
    CreateResultsListItem(e.Info);
}

The CreateResultsListItem method creates and adds a new ListViewItem to the results list, which shows the data contained in the FilesystemInfo object. A FileSystemInfo object can be either be a FileInfo or a DirectoryInfo, depending on what the Searcher has found. The is operator can be used to decide what kind of object it is. If it's a FileInfo object, the list shall display the file's size in KB:

C#
ListViewItem.ListViewSubItem lvsi = new ListViewItem.ListViewSubItem();
if (info is FileInfo)
{
    lvsi.Text = GetBytesStringKB(((FileInfo)info).Length);
}
else
{
    lvsi.Text = "";
}

When the Searcher's thread ends, it raises a ThreadEnded event, so the MainWindow recognizes when the search has ended. The Searcher_ThreadEnded event handler uses the Invoke method the same way as the Searcher_FoundInfo event handler:

C#
private delegate void ThreadEndedSyncHandler(ThreadEndedEventArgs e);
private ThreadEndedSyncHandler ThreadEnded;

...

private void MainWindow_Load(object sender, EventArgs e)
{
    ...
    this.ThreadEnded += new ThreadEndedSyncHandler(this_ThreadEnded);
    ...
}

...

private void Searcher_ThreadEnded(ThreadEndedEventArgs e)
{
    if (!m_closing)
    {
        this.Invoke(ThreadEnded, new object[] { e });
    }
}

private void this_ThreadEnded(ThreadEndedEventArgs e)
{
    EnableButtons();
    if (!e.Success)
    {
        MessageBox.Show(e.ErrorMsg,
                        "Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);
    }
}

Points of Interest

You can use this code as a simple example for a multithreading application.

History

  • April 6, 2009
    • Published at CodeProject
  • April 8, 2009
    • Change: Uses the Form.Invoke method instead of a System.Timers.Timer
    • New feature: "Open Containing Folder"
  • April 24, 2009
    • Bug-fix: Solved a dead lock bug that sometimes occured when the user clicks the "Stop" button.
    • New feature: Supports multiple file names, separated by ";". Example: "*.wav;*.mp3".
  • September 29, 2012
    • Upgraded solution to Visual Studio 2012. 
    • New feature: Write the search results to a text file.

License

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