This step-by-step article describes how to recursively search subfolders for files, beginning with a root folder, by using code. This task is known as directory recursion. You can specify a search string so that you can search for files that match a certain criteria. Each part of the code in this article is explained, and a working code sample is also provided.
Directory recursion is a common I/O task for developers. The
FileSystemObject object makes this task easy for Component Object Model (COM) programs, but this task is easier in Visual C++ .NET 2002. Similar to the
FileSystemObject object, the classes in the
System.IO namespace provide an object-oriented way to access files and folders.
Back to the topRequirements
The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:
- Microsoft Visual C++ .NET or Microsoft Visual C++ 2005
Back to the topEnable Directory Recursion
The file and directory manipulation classes reside in the
System::IO namespace. Before you work with these classes, add the following code:
using <mscorlib.dll>
using namespace System;
using namespace System::IO;
The
System::IO namespace provides many options for working with files and with folders. The
System::IO namespace not only provides classes that you can create an instance of, but it also provides file and directory utility classes. These classes contain static methods that you can call without having to declare a variable of that type. For example, you can use the
Directory class to obtain the subfolders of a folder.
The following code uses the static
GetDirectories method of the
Directory class to return an array of strings. This array contains folder paths to the subfolders of the C:\ folder, if any exist:
String* directories[] = Directory::GetDirectories("C:\\");
The
Directory class also contains the
GetFiles method. You can use
GetFiles to retrieve a string array of files that match a certain criteria. The following code sample uses the
GetFiles method to retrieve all files in the C:\ folder with a .dll file name extension:
String* files[] = Directory::GetFiles("C:\\", "*.dll");
You can use the
GetDirectories method and the
GetFiles method of the
Directory class to recursively search for files that match the search string. Use the following method to perform the recursion:
void DirSearch(String* sDir)
{
try
{
// Find the subfolders in the folder that is passed in.
String* d[] = Directory::GetDirectories(sDir);
int numDirs = d->get_Length();
for (int i=0; i < numDirs; i++)
{
// Find all the files in the subfolder.
String* f[] = Directory::GetFiles(d[i],textBox1->Text);
int numFiles = f->get_Length();
for (int j=0; j < numFiles; j++)
{
listBox1->Items->Add(f[j]);
}
DirSearch(d[i]);
}
}
catch (System::Exception* e)
{
MessageBox::Show(e->Message);
}
}
The previous code passes a string to the
DirSearch function. This string value is the full path of the folder that you want to search. You can use the
GetDirectories method to retrieve the subfolders of the folder that is passed into your procedure. Because the
GetDirectories method returns an array, you can use a
for statement to iterate over each subfolder. For each subfolder, use the
GetFiles method to iterate over the files in that folder. The value of the text box on your form is passed to the
GetFiles method. The text box contains the search string that filters the results that the
GetFiles method returns. When the file matches the search criteria, it is added to your list box. For each subfolder that is located, call the
DirSearch function again, and then pass a subfolder. You may use this recursive call to search all subfolders of a root folder that you specify.
Back to the topCreate the Sample
- Start Microsoft Visual Studio .NET 2003 or Microsoft Visual Studio 2005.
- On the File menu, point to
New, and then click Project. - Under Project Types, click
Visual C++ .NET.
Note In Microsoft Visual C++ 2005, Visual C++ .NET is changed to Visual C++. - Under Templates, click
Windows Forms Application (.NET). - In the Name box, type
RecursiveSearchCPP. In the Locatebox, type C:\, and then click
OK. - Open the Form1 form in Design view, and then press F4 to open the Properties window.
- In the Properties window, expand the Size folder. In the Width field, type
700. In the Height field, type
320. - Add two Label controls, one TextBox control, one
ComboBox control, one ListBox control, and one Button control to the Form1 form. - In the Properties window, change the
Location, the Size, the TabIndex, and the Text properties as follows:
Control ID | Location | Size | TabIndex | Text |
---|
label1 | 8, 16 | 144, 16 | 5 | Search for files that contain: |
textBox1 | 8, 40 | 120, 20 | 4 | *.dll |
label2 | 8, 96 | 120, 25 | 3 | Look in: |
button1 | 608, 248 | 75, 25 | 0 | &Search |
listBox1 | 152, 8 | 530, 225 | 1 | |
comboBox1 | 8, 128 | 120, 25 | 2 | C:\\ |
- In the InitializeComponent method for the combo box, add the following code to enlist all the network drives that are available on the computer:
// Enlist all the network drives that are available on the computer.
String* p_logicalDrives[] = __gc new String*[];
comboBox1->Items->Clear();
p_logicalDrives = Directory::GetLogicalDrives();
int numDrives = p_logicalDrives->get_Length();
for (int i=0; i< numDrives; i++)
{
comboBox1->Items->Add(p_logicalDrives[i]);
}
- Double-click on the Search button, and then paste the following code in the method:
// Clear the list box.
listBox1->Items->Clear();
// You do not have the option to change the values of the files to be searched
// until the search is completed. Therefore, the following value is false.
textBox1->Enabled = false;
comboBox1->Enabled = false;
button1->Text = S"Searching...";
this->Cursor = Cursors::WaitCursor;
Application::DoEvents();
// Callthe recursive search method.
DirSearch(comboBox1->Text);
button1->Text = S"Search";
this->Cursor = Cursors::Default;
// After the search is completed, the search criteria is enabled
//and you can add other search criteria to search the files recursively.
textBox1->Enabled = true;
comboBox1->Enabled = true;
- To build the application, press CTRL+F5 to build.
- Run the application.
Back to the topComplete Code Sample
// Form1.h
#pragma once
namespace RecursiveSearchCPP
{
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::IO;
/// <summary>
/// Summary for Form1
///
/// WARNING: If you change the name of this class, you must change the
/// Resource File Name property for the managed resource compiler tool
/// that is associated with all .resx files that this class depends on. Otherwise,
/// the designers will not be able to interact correctly with localized
/// resources that are associated with this form.
/// </summary>
public __gc class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
}
protected:
void Dispose(Boolean disposing)
{
// Form::Dispose(Disposing);
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing);
}
private: System::Windows::Forms::Label * label1;
private: System::Windows::Forms::TextBox * textBox1;
private: System::Windows::Forms::Label * label2;
private: System::Windows::Forms::Button * button1;
private: System::Windows::Forms::ListBox * listBox1;
private: System::Windows::Forms::ComboBox * comboBox1;
private:
/// <summary>
/// This is the required designer variable.
/// </summary>
System::ComponentModel::Container * components;
/// <summary>
/// This is the required method for Designer support. Do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->label1 = new System::Windows::Forms::Label();
this->textBox1 = new System::Windows::Forms::TextBox();
this->label2 = new System::Windows::Forms::Label();
this->button1 = new System::Windows::Forms::Button();
this->listBox1 = new System::Windows::Forms::ListBox();
this->comboBox1 = new System::Windows::Forms::ComboBox();
this->SuspendLayout();
//
// label1
//
this->label1->Location = System::Drawing::Point(8, 16);
this->label1->Name = S"label1";
this->label1->Size = System::Drawing::Size(144, 16);
this->label1->TabIndex = 5;
this->label1->Text = S"Search for files containing:";
//
// textBox1
//
this->textBox1->Location = System::Drawing::Point(8, 40);
this->textBox1->Name = S"textBox1";
this->textBox1->Size = System::Drawing::Size(120, 20);
this->textBox1->TabIndex = 4;
this->textBox1->Text = S"*.dll";
//
// label2
//
this->label2->Location = System::Drawing::Point(8, 96);
this->label2->Name = S"label2";
this->label2->Size = System::Drawing::Size(120, 23);
this->label2->TabIndex = 3;
this->label2->Text = S"Look in:";
//
// button1
//
this->button1->Location = System::Drawing::Point(608, 248);
this->button1->Name = S"button1";
this->button1->TabIndex = 0;
this->button1->Text = S"&Search";
this->button1->Click += new System::EventHandler(this, button1_Click);
//
// listBox1
//
this->listBox1->Location = System::Drawing::Point(152, 8);
this->listBox1->Name = S"listBox1";
this->listBox1->Size = System::Drawing::Size(530, 225);
this->listBox1->TabIndex = 1;
//
// comboBox1
//
// Enlist all the network drives that are available on the computer.
//
String* p_logicalDrives[] = __gc new String*[];
comboBox1->Items->Clear();
p_logicalDrives = Directory::GetLogicalDrives();
int numDrives = p_logicalDrives->get_Length();
for (int i=0; i< numDrives; i++)
{
comboBox1->Items->Add(p_logicalDrives[i]);
}
this->comboBox1->Location = System::Drawing::Point(8, 128);
this->comboBox1->Name = S"comboBox1";
this->comboBox1->Size = System::Drawing::Size(120, 25);
this->comboBox1->TabIndex = 2;
this->comboBox1->Text = S"C:\\";
//
// Form1
//
this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
this->ClientSize = System::Drawing::Size(688, 286);
this->Controls->Add(this->comboBox1);
this->Controls->Add(this->listBox1);
this->Controls->Add(this->button1);
this->Controls->Add(this->label2);
this->Controls->Add(this->textBox1);
this->Controls->Add(this->label1);
this->Name = S"Form1";
this->Text = S"Form1";
this->ResumeLayout(false);
}
private: System::Void button1_Click(System::Object * sender, System::EventArgs * e)
{
//Clears the list box
listBox1->Items->Clear();
// You do not have option to change the values of the files to be searched
// until the search is completed. Therefore, the value of the following is false.
textBox1->Enabled = false;
comboBox1->Enabled = false;
button1->Text = S"Searching...";
this->Cursor = Cursors::WaitCursor;
Application::DoEvents();
// Call the recursive search method.
DirSearch(comboBox1->Text);
button1->Text = S"Search";
this->Cursor = Cursors::Default;
// After the search is completed, the search criteria is enabled
// and you can add other search criteria to search the files recursively.
textBox1->Enabled = true;
comboBox1->Enabled = true;
}
void DirSearch(String* sDir)
{
try
{
// Find the subfolders in the folder that is passed in.
String* d[] = Directory::GetDirectories(sDir);
int numDirs = d->get_Length();
for (int i=0; i < numDirs; i++)
{
// Find all the files in the subfolder.
String* f[] = Directory::GetFiles(d[i],textBox1->Text);
int numFiles = f->get_Length();
for (int j=0; j < numFiles; j++)
{
listBox1->Items->Add(f[j]);
}
DirSearch(d[i]);
}
}
catch (System::Exception* e)
{
System::Console::WriteLine(e->Message);
}
}
};
}
//Form1.cpp
#include "stdafx.h"
#include "Form1.h"
#include <windows.h>
using namespace RecursiveSearchCPP;
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
System::Threading::Thread::CurrentThread->ApartmentState = System::Threading::ApartmentState::STA;
Application::Run(new Form1());
return 0;
}
Back to the top