简体   繁体   中英

C# Code takes to long to run. Is there a way to make it finish quicker?

I need some help. If you input an Directory into my code, it goes in every folder in that Directory and gets every single file. This way, i managed to bypass the "AccessDeniedException" by using a code, BUT if the Directory is one, which contains alot of Data and folders (example: C:/) it just takes way to much time.

I dont really know how to multithread and i could not find any help on the internet. Is there a way to make the code run faster by multithreading? Or is it possible to ask the code to use more memory or Cores? I really dont know and could use advise

My code to go in every File in every Subdirectory:

public static List<string> Files = new List<string>();
public static List<string> Exceptions = new List<string>();

public MainWindow()
{
    InitializeComponent();
}

private static void GetFilesRecursively(string Directory)
{
    try
    {
         foreach (string A in Directory.GetDirectories(Directory))
             GetFilesRecursively(A);

         foreach (string B in Directory.GetFiles(Directory))
             AddtoList(B);

    } catch (System.Exception ex) { Exceptions.Add(ex.ToString()); }
}

private static void AddtoList(string Result)
{
    Files.Add(Result);
}

private void Btn_Click(object sender, RoutedEventArgs e)
{
    GetFilesRecursively(Textbox1.Text);
    
    foreach(string C in Files)
       Textbox2.Text += $"{C} \n";
}

You don't need recursion to avoid inaccessible files. You can use the EnumerateFiles overload that accepts an EnumerationOptions parameter and set EnumerationOptions.IgnoreInaccessible to true :

var options=new EnumerationOptions 
            {
                IgnoreInaccessible=true,
                RecurseSubdirectories=true
            };
var files=Directory.EnumerateFiles(somePath,"*",options);

The loop that appends file paths is very expensive too. Not only does it create a new temporary string on each iteration, it also forces a UI redraw. You could improve speed and memory usage (which, due to garbage collection is also affecting performance) by creating a single string, eg with String.Join or a StringBuilder :

var text=String.Join("\n",files);
Textbox2.Text=text;

String.Join uses a StringBuilder internally whose internal buffer gets reallocated each time it's full. The previous buffer has to be garbage-collected. Once could avoid even this by using a StringBuilder with a specific capacity. Even a rough estimate can reduce reallocations significantly:

var builder=new StringBuilder(4096);
foreach(var file in files)
{
    builder.AppendLine(file);
}
  1. create a class so you can add a private field to count the deep of the directroy.
  2. add a TaskSource<T> property to the class, and await the Task that generated only if the deep out of the limit, and trigger an event so your UI can hook into the action and ask user.
  3. if user cancel, then the task fail, if user confirm, then continue.

some logic code

public class FileLocator
{
    public FileLocator(int maxDeep = 6){  
       _maxDeep = maxDeep; 
       this.TaskSource = new TaskSource();
       this.ConfirmTask  = this.TaskSource.Task;
    }
    private int _maxDeep;
    private int _deep;

    public event Action<FileLocator> OnReachMaxDeep;

    public Task ConfirmTask ;
    public TaskSource TaskSource {get;}

    public Task<List<string>> GetFilesRecursivelyAsync()
    {
       var result = new List<string>();
        foreach(xxxxxxx)
        {
            
            xxxxxxxxxxxxxx;
           this._deep +=1;
           if(_deep == _maxDeep)
           {  OnRichMaxDeep?.Invoke(this); }
           if(_deep >= _maxDeep)
           {
              try{
              await ConfirmTask;
              continue;
             }
             catch{
               return result;

            }
           }
        }
    }

}

and call

var locator = new FileLocator();

locator.OnReachMaxDeep += (x)=> {  var result =  UI.Confirm();  if(result){ x.TaskSource.SetResult(); else{  x.TaskSource.SetException(new Exception())   } }  }


var result = await locator.GetFilesRecursivelyAsync("C:");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM