Return to Snippet

Revision: 9886
at November 28, 2008 20:09 by jimfred


Updated Code
/// <summary>
/// Get a list of files based on filename-with-wildcard search criteria and file-content search criteria.
/// Regular expressions are not supported (yet).
/// Calls System.IO.Directory.GetFiles to get files.
/// Calls System.IO.File.ReadAllText().Contains to search contents.
/// Uses ToLower() to perform case-insensitive search.
/// </summary>
/// <param name="directoryArg">Directory to start search, such as @"C:\" or Environment.GetEnvironmentVariable("SystemRoot")</param>
/// <param name="containsTextArg">Test to search for. "" will be found in any file.</param>
/// <param name="ignoreCaseArg"></param>
/// <param name="searchSubDirsArg"></param>
/// <param name="fileWildcardsArg">Can be an array of files or a single file such as "*.ini"</param>
/// <returns>a list of files (complete paths) found.</returns>
static IEnumerable<string> FindInFiles( 
    string                 directoryArg,
    string                 containsTextArg,
    bool                   ignoreCaseArg,
    System.IO.SearchOption searchSubDirsArg,
    params string[]        fileWildcardsArg )
{
    List<String> files = new List<string>(); // This List accumulates files found.
    
    foreach (string fileWildcard in fileWildcardsArg )
    {
        string[] xFiles = System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg);

        foreach ( string x in xFiles )
        {
            if ( !files.Contains(x) ) // If file not already found...
            {
                // See if the file contains the search text.
                // Assume a null search string matches any file.
                // Use ToLower to perform a case-insensitive search.
                bool containsText = 
                    containsTextArg.Length==0 ||
                    ignoreCaseArg ? 
                    System.IO.File.ReadAllText(x).ToLower().Contains(containsTextArg.ToLower()) : 
                    System.IO.File.ReadAllText(x).Contains(containsTextArg);

                if ( containsText )
                {
                    files.Add(x); // This file is a keeper. Add it to the list.
                } // if
            } // if
        } // foreach file
    } foreach wildcard
    return files;
}

/////////////////////////////////////////
// LINQ-uified version of same function...
/////////////////////////////////////////
static IEnumerable<string> FindInFiles( 
    string                 directoryArg,
    string                 containsTextArg,
    bool                   ignoreCaseArg,
    System.IO.SearchOption searchSubDirsArg,
    params string[]        fileWildcardsArg )
{

    IEnumerable<string> files =
        from fileWildcard in fileWildcardsArg
        from file in System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg)
        where
            containsTextArg.Length == 0 ||
            ignoreCaseArg ?
            System.IO.File.ReadAllText(file).ToLower().Contains(containsTextArg.ToLower()) :
            System.IO.File.ReadAllText(file).Contains(containsTextArg)
        select file;

    return files;
}


/// LinqPad syntax for testing/debugging:
var fileWildcardsArg = new[] { "OEM*.inf" }.AsQueryable();
var directoryArg = Environment.GetEnvironmentVariable("SystemRoot");
var searchSubDirsArg = System.IO.SearchOption.AllDirectories;
var containsTextArg = "VID_08b1";
var ignoreCaseArg = true;

IEnumerable<string> files =
	from fileWildcard in fileWildcardsArg
	from file in System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg)
	where
		containsTextArg.Length == 0 ||
		ignoreCaseArg ?
		System.IO.File.ReadAllText(file).ToLower().Contains(containsTextArg.ToLower()) :
		System.IO.File.ReadAllText(file).Contains(containsTextArg)
	select file;

files.Dump();

Revision: 9885
at November 28, 2008 18:32 by jimfred


Updated Code
/// <summary>
/// Get a list of files based on filename-with-wildcard search criteria and file-content search criteria.
/// Regular expressions are not supported (yet).
/// Calls System.IO.Directory.GetFiles to get files.
/// Calls System.IO.File.ReadAllText().Contains to search contents.
/// Uses ToLower() to perform case-insensitive search.
/// </summary>
/// <param name="directoryArg">Directory to start search, such as @"C:\" or Environment.GetEnvironmentVariable("SystemRoot")</param>
/// <param name="containsTextArg">Test to search for. "" will be found in any file.</param>
/// <param name="ignoreCaseArg"></param>
/// <param name="searchSubDirsArg"></param>
/// <param name="fileWildcardsArg">Can be an array of files or a single file such as "*.ini"</param>
/// <returns>a list of files (complete paths) found.</returns>
static IEnumerable<string> FindInFiles( 
    string                 directoryArg,
    string                 containsTextArg,
    bool                   ignoreCaseArg,
    System.IO.SearchOption searchSubDirsArg,
    params string[]        fileWildcardsArg )
{
    List<String> files = new List<string>(); // This List accumulates files found.
    
    foreach (string fileWildcard in fileWildcardsArg )
    {
        string[] xFiles = System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg);

        foreach ( string x in xFiles )
        {
            if ( !files.Contains(x) ) // If file not already found...
            {
                // See if the file contains the search text.
                // Assume a null search string matches any file.
                // Use ToLower to perform a case-insensitive search.
                bool containsText = 
                    containsTextArg.Length==0 ||
                    ignoreCaseArg ? 
                    System.IO.File.ReadAllText(x).ToLower().Contains(containsTextArg.ToLower()) : 
                    System.IO.File.ReadAllText(x).Contains(containsTextArg);

                if ( containsText )
                {
                    files.Add(x); // This file is a keeper. Add it to the list.
                } // if
            } // if
        } // foreach file
    } foreach wildcard
    return files;
}

/////////////////////////////////////////
// LINQ-uified version of same function...
/////////////////////////////////////////
static IEnumerable<string> FindInFiles( 
    string                 directoryArg,
    string                 containsTextArg,
    bool                   ignoreCaseArg,
    System.IO.SearchOption searchSubDirsArg,
    params string[]        fileWildcardsArg )
{

    IEnumerable<string> files =
        from fileWildcard in fileWildcardsArg
        from file in System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg)
        where
            containsTextArg.Length == 0 ||
            ignoreCaseArg ?
            System.IO.File.ReadAllText(file).ToLower().Contains(containsTextArg.ToLower()) :
            System.IO.File.ReadAllText(file).Contains(containsTextArg)
        select file;

    return files;
}

Revision: 9884
at November 28, 2008 16:50 by jimfred


Updated Code
/// <summary>
/// Get a list of files based on filename-with-wildcard search criteria and file-content search criteria.
/// Regular expressions are not supported (yet).
/// Calls System.IO.Directory.GetFiles to get files.
/// Calls System.IO.File.ReadAllText().Contains to search contents.
/// Uses ToLower() to perform case-insensitive search.
/// </summary>
/// <param name="directoryArg">Directory to start search, such as @"C:\" or Environment.GetEnvironmentVariable("SystemRoot")</param>
/// <param name="containsTextArg">Test to search for. "" will be found in any file.</param>
/// <param name="ignoreCaseArg"></param>
/// <param name="searchSubDirsArg"></param>
/// <param name="fileWildcardsArg">Can be an array of files or a single file such as "*.ini"</param>
/// <returns>a list of files (complete paths) found.</returns>
static IEnumerable<string> FindInFiles( 
    string                 directoryArg,
    string                 containsTextArg,
    bool                   ignoreCaseArg,
    System.IO.SearchOption searchSubDirsArg,
    params string[]        fileWildcardsArg )
{
    List<String> files = new List<string>(); // This List accumulates files found.
    
    foreach (string fileWildcard in fileWildcardsArg )
    {
        string[] xFiles = System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg);

        foreach ( string x in xFiles )
        {
            if ( !files.Contains(x) ) // If file not already found...
            {
                // See if the file contains the search text.
                // Assume a null search string matches any file.
                // Use ToLower to perform a case-insensitive search.
                bool containsText = 
                    containsTextArg.Length==0 ||
                    ignoreCaseArg ? 
                    System.IO.File.ReadAllText(x).ToLower().Contains(containsTextArg.ToLower()) : 
                    System.IO.File.ReadAllText(x).Contains(containsTextArg);

                if ( containsText )
                {
                    files.Add(x); // This file is a keeper. Add it to the list.
                } // if
            } // if
        } // foreach file
    } foreach wildcard
    return files;
}

/////////////////////////////////////////
// LINQ-ified version of same function...
/////////////////////////////////////////
static IEnumerable<string> FindInFiles( 
    string                 directoryArg,
    string                 containsTextArg,
    bool                   ignoreCaseArg,
    System.IO.SearchOption searchSubDirsArg,
    params string[]        fileWildcardsArg )
{

    IEnumerable<string> files =
        from fileWildcard in fileWildcardsArg
        from file in System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg)
        where
            containsTextArg.Length == 0 ||
            ignoreCaseArg ?
            System.IO.File.ReadAllText(file).ToLower().Contains(containsTextArg.ToLower()) :
            System.IO.File.ReadAllText(file).Contains(containsTextArg)
        select file;

    return files;
}

Revision: 9883
at November 28, 2008 03:03 by jimfred


Updated Code
/// <summary>
/// Get a list of files based on filename-with-wildcard search criteria and file-content search criteria.
/// Regular expressions are not supported (yet).
/// Calls System.IO.Directory.GetFiles to get files.
/// Calls System.IO.File.ReadAllText().Contains to search contents.
/// Uses ToLower() to perform case-insensitive search.
/// </summary>
/// <param name="directoryArg">Directory to start search, such as @"C:\" or Environment.GetEnvironmentVariable("SystemRoot")</param>
/// <param name="containsTextArg">Test to search for. "" will be found in any file.</param>
/// <param name="ignoreCaseArg"></param>
/// <param name="searchSubDirsArg"></param>
/// <param name="fileWildcardsArg">Can be an array of files or a single file such as "*.ini"</param>
/// <returns>a list of files (complete paths) found.</returns>
static IEnumerable<string> FindInFiles( 
    string                 directoryArg,
    string                 containsTextArg,
    bool                   ignoreCaseArg,
    System.IO.SearchOption searchSubDirsArg,
    params string[]        fileWildcardsArg )
{
    List<String> files = new List<string>(); // This List accumulates files found.
    
    foreach (string fileWildcard in fileWildcardsArg )
    {
        string[] xFiles = System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg);

        foreach ( string x in xFiles )
        {
            if ( !files.Contains(x) ) // If file not already found...
            {
                // See if the file contains the search text.
                // Assume a null search string matches any file.
                // Use ToLower to perform a case-insensitive search.
                bool containsText = 
                    containsTextArg.Length==0 ||
                    ignoreCaseArg ? 
                    System.IO.File.ReadAllText(x).ToLower().Contains(containsTextArg.ToLower()) : 
                    System.IO.File.ReadAllText(x).Contains(containsTextArg);

                if ( containsText )
                {
                    files.Add(x); // This file is a keeper. Add it to the list.
                } // if
            } // if
        } // foreach file
    } foreach wildcard
    return files;
}

Revision: 9882
at November 28, 2008 02:59 by jimfred


Initial Code
/// <summary>
/// Get a list of files based on filename-with-wildcard search criteria and file-content search criteria.
/// Regular expressions are not supported (yet).
/// Calls System.IO.Directory.GetFiles to get files.
/// Calls System.IO.File.ReadAllText().Contains to search contents.
/// Uses ToLower() to perform case-insensitive search.
/// </summary>
/// <param name="directoryArg">Directory to start search, such as @"C:\" or Environment.GetEnvironmentVariable("SystemRoot")</param>
/// <param name="containsTextArg">Test to search for. "" will be found in any file.</param>
/// <param name="ignoreCaseArg"></param>
/// <param name="searchSubDirsArg"></param>
/// <param name="fileWildcardsArg">Can be an array of files or a single file such as "*.ini"</param>
/// <returns>a list of files (complete paths) found.</returns>
static IEnumerable<string> FindInFiles( 
    string                 directoryArg,
    string                 containsTextArg,
    bool                   ignoreCaseArg,
    System.IO.SearchOption searchSubDirsArg,
    params string[]        fileWildcardsArg )
{
    List<String> files = new List<string>(); // This List accumulates files found.
    
    foreach (string fileWildcard in fileWildcardsArg )
    {
        string[] xFiles = System.IO.Directory.GetFiles(directoryArg, fileWildcard, searchSubDirsArg);

        foreach ( string x in xFiles )
        {
            if ( !files.Contains(x) )
            {
                bool containsText = 
                    containsTextArg.Length==0 ||
                    ignoreCaseArg ? 
                    System.IO.File.ReadAllText(x).ToLower().Contains(containsTextArg.ToLower()) : 
                    System.IO.File.ReadAllText(x).Contains(containsTextArg);

                if ( containsText )
                {
                    files.Add(x);
                }
            }
        }
    }
    return files;
}

Initial URL


Initial Description
This function provides C# with functionality similar to the apparently deprecated my.Computer.FileSystem.FindInFiles under the Microsoft.VisualBasic namespace. 

Example usage:
            IEnumerable<string> oemFiles = FindInFiles(
                Environment.GetEnvironmentVariable("SystemRoot"),
                "VID_08b1",
                false,
                System.IO.SearchOption.AllDirectories,
                "OEM*.INF"
            );

There are two implementations in Source: [1] foreach and [2] LINQ-uified. The foreach version has nested foreach loops: one for the fileWildcards and one to search the contents of the files. There's an if statement that prevents duplicates. The LINQ-uified version is also nested - it has nested from clauses.

The LINQ-uified version is definitely more concise. It's harder to debug - can't really be stepped-through. This seems to be the classic trade-off between the imperative foreach approach and the functional LINQ approach.

Source also contains LinqPad syntax. LinqPad can be downloaded at http://www.linqpad.net/. It'll translate from LINQ to Lambda but I think Lambda is harder to read.

Initial Title
FindInFiles, C# static function

Initial Tags
c

Initial Language
C#