Friday, February 9, 2007

Search and Replace Texts in all Files and Subfolders using C#

Recently I needed to replace a string in whole bunch of HTML template files that I had been working on. I found a couple of text editors which attempted to do this only after loading the entire lot of files in the memory. When the number of files were in hundreds they failed miserably. I also tried to load the files into a project in Visual Studio 2005 IDE and use its Find & Replace in Current Project feature. This failed to find texts with line breaks eventually forcing me to drop this idea. After spending an hour of intense googling to find the right tool, I decided to make my own Search & Replace application in C# and I did make it in 15mins. This application can search and replace texts in all files and subfolders filtered by their extensions. 

Instead of using the string.Replace() method provided by the string object, I wrote a custom method which finds and replace strings  in a loop. This gives me more flexibility to keep track of the number of replacements as well as the files that were actually affected. The Directory.GetFiles() method returns the complete paths of all files (after applying the filter) in the specified folder and all its subfolders.

Here is The code....

private void btnReplace_Click(object sender, EventArgs e)
{
    //Enter some text that you want to search and replace
    string find = txtFind.Text; 
    int replaced = 0;

    //Get all the files from the root directory filtered by a filter text.
    string[] fileList = Directory.GetFiles(@"C:\Documents and Settings\tganesan\Desktop\FindnReplace", "*.txt", SearchOption.AllDirectories);

    //Loop through each file, call the ReplaceText() method
    //and replace the file if something was replaced.
    foreach (string file in fileList)
    {
       StreamReader sr = new StreamReader(file);
       string content = sr.ReadToEnd();
       sr.Close();
       
       if(ReplaceText(ref content, txtFind.Text, txtReplace.Text, ref replaced))
       {
           StreamWriter sw = new StreamWriter(file);
           sw.Write(content);
           sw.Flush();
           sw.Close();
           //TODO: Add the files to a collection that were affected.
       }               
    }
    MessageBox.Show("Total replacements = " + replaced);
}


/// <summary>
/// This method loops through the File content 
/// and replaces the text if found.
/// </summary>
/// <param name="content"></param>
/// <param name="oldValue"></param>
/// <param name="newValue"></param>
/// <param name="replaced"></param>
/// <returns></returns>
private bool ReplaceText(ref string content,string oldValue, string newValue, ref int replaced)
{
    Boolean isReplaced = false;
    int startIndex = 0;         

    while (startIndex != -1)
    {
        startIndex = content.IndexOf(oldValue,startIndex);
        if (startIndex != -1)
        {
            content = content.Remove(startIndex, oldValue.Length);
            content = content.Insert(startIndex,newValue);                    
            replaced += 1;
            isReplaced = true;
        }
    }
    return isReplaced;
}
Don't forget to take a backup of files before running this code.

No comments: