如何在完成之前访问DirectoryInfo.EnumerateFiles

Gen*_*rey 3 .net c# io winforms

在我问的问题中快速检索文件夹和所有子文件夹中的文件名列表和我发现的其他一些文件,似乎搜索许多文件的方法是使用EnumerateFiles方法.

EnumerateFiles和GetFiles方法的不同之处如下:当您使用EnumerateFiles时,您可以在返回整个集合之前开始枚举名称集合; 当您使用GetFiles时,您必须等待返回整个名称数组,然后才能访问该数组.因此,当您使用许多文件和目录时,EnumerateFiles可以更高效.

这对我来说听起来很棒,我的搜索大约需要10秒钟,因此我可以在信息输入时开始设置我的列表.但我无法理解.当我运行EnumerateFiles方法时,应用程序冻结直到它完成.我可以在后台工作程序中运行它,但同样的事情将发生在该线程中.有帮助吗?

 DirectoryInfo dir = new DirectoryInfo(MainFolder);
 List<FileInfo> matches = new List<FileInfo>(dir.EnumerateFiles("*.docx",SearchOption.AllDirectories));

//This wont fire until after the entire collection is complete
DoSoemthingWhileWaiting();
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 11

您可以通过将其推送到后台任务来完成此操作.

例如,您可以这样做:

var fileTask = Task.Factory.StartNew( () =>
{
    DirectoryInfo dir = new DirectoryInfo(MainFolder);
    return new List<FileInfo>(
           dir.EnumerateFiles("*.docx",SearchOption.AllDirectories)
           .Take(200) // In previous question, you mentioned only wanting 200 items
       );
};

// To process items:
fileTask.ContinueWith( t =>
{
     List<FileInfo> files = t.Result;

     // Use the results...
     foreach(var file in files)
     {
         this.listBox.Add(file); // Whatever you want here...
     }
}, TaskScheduler.FromCurrentSynchronizationContext()); // Make sure this runs on the UI thread

DoSomethingWhileWaiting();
Run Code Online (Sandbox Code Playgroud)

你在评论中提到:

我想在列表中显示它们.当他们进来时,完美地将他们送到主要的ui

在这种情况下,您必须在后台处理它们,并在它们进入时将它们添加到列表中.类似于:

Task.Factory.StartNew( () =>
{
    DirectoryInfo dir = new DirectoryInfo(MainFolder);
    foreach(var tmp in dir.EnumerateFiles("*.docx",SearchOption.AllDirectories).Take(200))
    {
        string file = tmp; // Handle closure issue

        // You may want to do this in batches of >1 item...
        this.BeginInvoke( new Action(() =>
        {
             this.listBox.Add(file);
        }));
    }
});
DoSomethingWhileWaiting();
Run Code Online (Sandbox Code Playgroud)


Dar*_*rov 7

该应用程序冻结,因为您通过将它放在该构造函数中来消耗此枚举List<FileInfo>.就好像你急切地呼唤旧方法一样.因此,执行此操作的正确方法是在后台线程中运行它,然后不要立即将结果传递给将使用可枚举的内容直到结束,但是当它们到达循环时开始迭代并添加项目.

我可以在后台工作程序中运行它,但同样的事情将发生在该线程中.

是的,在循环中你显然会冻结后台线程,但这是后台线程的意思:避免冻结主UI线程.只需确保在将项目传递给主线程时向他们展示您正在使用与UI的正确同步.在WinForms中,这发生在Control.Invoke方法中.当然要小心,因为在后台线程和UI线程之间经常进行编组也会产生负面影响,让您觉得应用程序冻结了.要解决此问题,您可以在文件到达时传递文件.

这是一个例子:

Task.Factory.StartNew(() =>
{
    var dir = new DirectoryInfo(MainFolder);
    var files = dir.EnumerateFiles("*.docx", SearchOption.AllDirectories);
    foreach (var file in files)
    {
        Action<string> del = f => listBox1.Items.Add((string)f);
        BeginInvoke(del, file);
    }
});
Run Code Online (Sandbox Code Playgroud)