Recursively search for files and replace text in them in C#

This program recursively searches a directory subtree for files matching one or more patterns. Optionally it replaces instances of a target string in those files with a new string.

Both the Find and Find & Replace buttons call the SearchForFiles method. The only difference is that the Find button passes that method a null parameter for the "replace with" string.

The following code shows the SearchForFiles method.

// Find files matching the pattern that contain the target string
// and make the replacement if appropriate.
private void SearchForFiles(ListBox lst, string start_dir,
string pattern, string from_string, string to_string)
{
try
{
// Clear the result ListBox.
lstFiles.Items.Clear();

// Parse the patterns.
string[] patterns = ParsePatterns(pattern);

// If from_string is blank, don't replace.
if (from_string.Length < 1) from_string = null;

DirectoryInfo dir_info = new DirectoryInfo(start_dir);
SearchDirectory(lst, dir_info, patterns, from_string, to_string);

if (from_string == null)
{
MessageBox.Show("Found " + lst.Items.Count + " files.");
}
else
{
MessageBox.Show("Made replacements in " + lst.Items.Count + " files.");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

The SearchForFiles method clears the program's result ListBox. It then calls ParsePatterns to convert the file search pattern into an array of patterns. For example, if the pattern is "Text Files (*.rtf, *.txt)" then ParsePatterns returns an array holding the values *.rtf and *.txt. (Parse pattern uses the String class's IndexOf, SubString, and Split methods. It's not too complex so it isn't shown here. Download the example and look at the code to see how it works.)

Next SearchForFiles creates a DirectoryInfo object representing the directory whose name the user entered. It then calls the SearchDirectory method to do most of the real work.

The following code shows the SearchDirectory method.

// Find files matching the pattern that contain the target string
// and make the replacement if appropriate.
private void SearchDirectory(ListBox lst, DirectoryInfo dir_info,
string[] patterns, string from_string, string to_string)
{
// Search this directory.
foreach (string pattern in patterns)
{
// Check this pattern.
foreach (FileInfo file_info in dir_info.GetFiles(pattern))
{
// Process this file.
ProcessFile(lst, file_info, from_string, to_string);
}
}

// Search subdirectories.
foreach (DirectoryInfo subdir_info in dir_info.GetDirectories())
{
SearchDirectory(lst, subdir_info, patterns, from_string, to_string);
}
}

First the method processes this directory's files. For each file pattern, the code uses GetFiles to get the files that match the pattern. For each file, the code calls ProcessFile to process the file.

After it processes the files, the code loops through this directory's subdirectories calling SearchDirectory for each.

The following code shows the ProcessFile method.

// Replace all occurrences of from_string with to_string.
// Return true if there was a problem and we should stop.
private void ProcessFile(ListBox lst, FileInfo file_info, string from_string, string to_string)
{
try
{
if (from_string == null)
{
// Add the file to the list.
lst.Items.Add(file_info.FullName);
}
else
{
// See if the file contains from_string.
string txt = System.IO.File.ReadAllText(file_info.FullName);
if (txt.Contains(from_string))
{
// Add the file to the list.
lst.Items.Add(file_info.FullName);

// See if we should make a replacement.
if (to_string != null)
{
System.IO.File.WriteAllText(file_info.FullName,
txt.Replace(from_string, to_string));
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error processing file " +
file_info.FullName + "\n" + ex.Message);
}
}

If from_string is null, the program should find all files without checking to see whether they contain a target string (because there isn't one). In that case, the program simply adds the file's name to the result ListBox.

If from_string is not null, the code reads the file into a string and sees whether it contains from_string. If the file does contain from_string, the code adds the file's name to the list. If to_string is also not null, the code replaces from_string with to_string in the text and writes the text back into the file.

Note that this code will try to read and process files that are not text files. For example, it will read RTF files. This way will often succeed, although it may be confused by binary data or codes (such as RTF codes) in the file. Searching for files will probably still not cause problems, but you should be careful when you make replacements in non-text files because the program may mess up codes.

   

 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this post.
Comments
  • No comments exist for this post.
Leave a comment

Submitted comments are subject to moderation before being displayed.

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.