Title: Find files and replace text in them in C#
The File Explorer in Windows seems to get worse at searching for files with every new version. It's always been pretty flaky, sometimes finding files and sometimes not. Lately it seems mostly not.
This program lets you recursively find files in a directory hierarchy that match one or more patterns. You can then replace text in those files with new text.
Both the Find and the 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 you entered. It then calls the following SearchDirectory method to do most of the real work.
// 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 = 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)
{
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 a target string). 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 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.
Download the example to experiment with it and to see additional details.
|