user2439970
user2439970

Reputation: 129

Why is this c# code so slow? Optimisation on directory/file searching & adding needed

I've written up some fairly quick-ish code and ever since changing it to "SearchOption.AllDirectories", it takes a whole minute to even just load the form/application.

Is there something I can do to make this application run faster on load? Any help/information would be appreciated.

Thanks.

private const string path = @"R:\Folder One\Folder Two\Folder Three";

public frmMain()
{
    InitializeComponent();

    ListDirectory(treeView1, path);
    treeView1.SelectedNode = treeView1.Nodes[0];
    treeView1.SelectedNode.Expand();
}

private void ListDirectory(TreeView treeView, string path)
{
    treeView.Nodes.Clear();
    var rootDirectoryInfo = new DirectoryInfo(path);
    treeView.Nodes.Add(CreateDirectoryNode(rootDirectoryInfo));
}

private TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
    var directoryNode = new TreeNode(directoryInfo.Name);
    foreach (var directory in directoryInfo.GetDirectories())
    {
        if (!directory.Name.Contains("_") 
             && !directory.Name.Contains("Word Versions") 
             && !directory.Name.Contains("Visio Flowcharts"))
        {
            var dirFileCount = directory.EnumerateFiles(
                         "*.pdf", SearchOption.AllDirectories).Count();
            dirFileCount += directory.EnumerateFiles(
                         "*.xls", SearchOption.AllDirectories).Count();
            dirFileCount += directory.EnumerateFiles(
                         "*.doc", SearchOption.AllDirectories).Count();
            dirFileCount += directory.EnumerateFiles(
                         "*.xlsx", SearchOption.AllDirectories).Count();
            dirFileCount += directory.EnumerateFiles(
                         "*.docx", SearchOption.AllDirectories).Count();
            dirFileCount += directory.EnumerateFiles(
                         "~*", SearchOption.AllDirectories).Count();

            if (dirFileCount != 0)
                directoryNode.Nodes.Add(CreateDirectoryNode(directory));
        }
    }

    foreach (var file in directoryInfo.GetFiles())
    {
        if (file.Extension.Equals(".pdf") 
           || file.Extension.Equals(".xls") 
           || file.Extension.Equals(".doc") 
           || file.Extension.Equals(".xlsx") 
           || file.Extension.Equals(".docx"))
        {
            if (!file.Name.Contains("~") 
                        || !file.Name.Contains("$"))
                directoryNode.Nodes.Add(new TreeNode(file.Name));
        }
    }
    return directoryNode;
}

Upvotes: 1

Views: 1462

Answers (4)

arvinth
arvinth

Reputation: 1

int doc_filescount = directory_info.GetFileSystemInfos("*.doc").Length;

IT will produce both (".doc" and ".docx") files count in a directory

Upvotes: -1

xanatos
xanatos

Reputation: 111820

This:

var dirFileCount = directory.EnumerateFiles("*.pdf", SearchOption.AllDirectories).Count();
dirFileCount += directory.EnumerateFiles("*.xls", SearchOption.AllDirectories).Count();
dirFileCount += directory.EnumerateFiles("*.doc", SearchOption.AllDirectories).Count();
dirFileCount += directory.EnumerateFiles("*.xlsx", SearchOption.AllDirectories).Count();
dirFileCount += directory.EnumerateFiles("*.docx", SearchOption.AllDirectories).Count();
dirFileCount += directory.EnumerateFiles("~*", SearchOption.AllDirectories).Count();

if (dirFileCount != 0)
    directoryNode.Nodes.Add(CreateDirectoryNode(directory));

is totally w r o n g.

Each EnumerateFiles will rescan all the subdirectories for a certain type of file. Even worse: you are counting how many files you have in total of that types, but what you want is "is there any file of that extensions"? So after finding the first file .pdf you could stop.

You should search for "*" and then filter by the extensions you want, stopping at the first file found.

This

var dirFileCount = from p in directory.EnumerateFiles("*", SearchOption.AllDirectories)
                   let extension = p.Extension
                   where extension.Equals("pdf", StringComparison.OrdinalIgnoreCase) ||
                         extension.Equals("xls", StringComparison.OrdinalIgnoreCase) ||
                         extension.Equals("doc", StringComparison.OrdinalIgnoreCase) ||
                         extension.Equals("xlsx", StringComparison.OrdinalIgnoreCase) ||
                         p.Name.StartsWith("~")
                   select p;

if (dirFileCount.Any())
{
    directoryNode.Nodes.Add(CreateDirectoryNode(directory));
}

is probably better.

And are you sure you have to search in subfolders? Because SearchOption.AllDirectories will search in subfolders, and not only in the given folder.

Upvotes: 5

Luca
Luca

Reputation: 1626

Run your code in a separate thread

Thread yourThread = new System.Threading.Thread(delegate(){
          //Your code 
 });
yourThread.Start();

Be care when updating main thread controls, you need to use Invoke , for example in a WPF app

Dispatcher.Invoke(new Action(delegate()
                 // your code that update main thread controls
                {}));

Upvotes: 0

Adriaan Stander
Adriaan Stander

Reputation: 166346

Why dont you just load the root directory on form load, and then load each sub node once the user expands that node.

Further to that, why dont you look at using BackgroundWorker Class to make the Userinterface more interactive?

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.

Upvotes: 0

Related Questions