Mohammed Al-Hagree
Mohammed Al-Hagree

Reputation: 33

How to make a program search for a file quickly

I wrote a program looking for a specific file in the computer, but it suffers from slow and delays in obtaining the many files on your computer

This function is working to get all the files

void Get_Files(DirectoryInfo D)
        {
            FileInfo[] Files;
            try
            {
                Files = D.GetFiles("*.*");
                foreach (FileInfo File_Name in Files)
                    listBox3.Items.Add(File_Name.FullName);
            }
            catch { }

            DirectoryInfo[] Dirs;
            try
            {
                Dirs = D.GetDirectories();
                foreach (DirectoryInfo Dir in Dirs)
                {
                    if (!(Dir.ToString().Equals("$RECYCLE.BIN")) && !(Dir.ToString().Equals("System Volume Information")))
                        Get_Files(Dir);
                }
            }
            catch { }
        }

Is there another way to get a little faster all the computer files??

Upvotes: 3

Views: 2438

Answers (5)

Ňuf
Ňuf

Reputation: 6207

Use profiler to find out, what operation is the slowest. Then think about how to make it faster. Otherwise you can waste your time by optimizing something, that is not bottleneck and will not bring you expected speed up.

In your case, you will probably find, that when you call this function for the first time (when directory structure is not in cache), most time will be spent in GetDirectories() and GetFiles() functions. You can pre-cache list of all files in memory (or in database) and use FileSystemWatcher to monitor changes in filesystem to update your file list with new files. Or you can use existing services, such as Windows Indexing service, but these may not be available on every computer.

Second bottleneck could be adding files to ListBox. If number of added item is large, you can temporarily disable drawing of listbox using ListBox.BeginUpdate and when you finish, enable it again with ListBox.EndUpdate. This can sometimes lead to huge speed up.

Upvotes: 2

Kane
Kane

Reputation: 16802

You will find much faster performance using Directory.GetFiles() as the FileInfo and DirectoryInfo classes get extra information from the file system which is much slower than simply than returning the string based file name.

Here is a code example that should yield much improved results and abstracts the action of retrieving files from the operation of displaying them in a list box.

static void Main(string[] args)
{
    var fileFinder = new FileFinder(@"c:\SomePath");
    listBox3.Items.Add(fileFinder.Files);
}

/// <summary>
/// SOLID: This class is responsible for recusing a directory to return the list of files, which are 
/// not in an predefined set of folder exclusions.
/// </summary>
internal class FileFinder
{
    private readonly string _rootPath;
    private List<string> _fileNames;
    private readonly IEnumerable<string> _doNotSearchFolders = new[] { "System Volume Information", "$RECYCLE.BIN" };

    internal FileFinder(string rootPath)
    {
        _rootPath = rootPath;
    }

    internal IEnumerable<string> Files
    {
        get
        {
            if (_fileNames == null)
            {
                _fileNames = new List<string>();
                GetFiles(_rootPath);
            }

            return _fileNames;
        }
    }

    private void GetFiles(string path)
    {
        _fileNames.AddRange(Directory.GetFiles("*.*"));

        foreach (var recursivePath in Directory.GetDirectories(path).Where(_doNotSearchFolders.Contains))
        {
            GetFiles(recursivePath);
        }
    }
}

Upvotes: 0

Chris Dunaway
Chris Dunaway

Reputation: 11216

Part of the problem is that the GetFiles method doesn't return until it has gotten all the files in the folder and if you are performing a recursive search, then for each sub folder you recurse into, it will take longer and longer.

Look into using DirectoryInfo.EnumerateFile or DirectoryInfo.EnumerateFileSystemInfos

From the docs:

The EnumerateFiles and GetFiles methods differ as follows: When you use EnumerateFiles, you can start enumerating the collection of FileInfo objects before the whole collection is returned; when you use GetFiles, you must wait for the whole array of FileInfo objects to be returned before you can access the array. Therefore, when you are working with many files and directories, EnumerateFiles can be more efficient.

The same is true for EnumerateFileSystemInfos

You can also look into querying the Indexing Service (if it is installed and running). See this article on CodeProject:

http://www.codeproject.com/Articles/19540/Microsoft-Indexing-Service-How-To

I found this by Googling "How to query MS file system index"

Upvotes: 1

usr
usr

Reputation: 171178

You can enumerate all files once and store the list.

But if you can't do that, this is basically as good as it gets. You can do two small things:

  • Try using threads. This will get much better on an SSD but might hurt on a rotating disk
  • Use DirectoryInfo.GetFileSystemEntries. This will return files and dirs in one efficient call.

Upvotes: 0

George Skoptsov
George Skoptsov

Reputation: 3951

The answer will generally depend on your operating system. In any case you will want to build and maintain your own database of files; explicit search like in your example will be too costly and slow.

A standard solution on Linux (and Mac OS X, if I'm not mistaken) is to maintain a locatedb file, which is updated by the system on a regular basis. If run on these systems, your program could make queries against this database.

Upvotes: 1

Related Questions