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

本文关键字:访问 DirectoryInfo EnumerateFiles | 更新日期: 2023-09-27 18:34:10

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

枚举文件和获取文件方法的区别如下: 当你 使用枚举文件,可以开始枚举名称的集合 在全部藏品归还之前; 当您使用 GetFiles 时,您 必须等待返回整个名称数组,然后才能 访问阵列。因此,当您处理许多文件和 目录,枚举文件可以更有效率。

这对我来说听起来很棒,我的搜索大约需要 10 秒,所以我可以在信息进来时开始整理我的列表。 但是我想不通。 当我运行枚举文件方法时,应用程序冻结,直到它完成。 我可以在后台工作线程中运行它,但同样的事情也会发生在该线程上。 有什么帮助吗?

 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();

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

可以通过将其推送到后台任务来执行此操作。

例如,您可以执行以下操作:

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();

您在评论中提到:

我想在列表中显示它们。 并在它们进来时完美地将它们发送到主 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();

应用程序冻结,因为您通过将枚举对象放入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);
    }
});

你可以做

    forach(var f in dir.EnumerateFiles("*.docx",SearchOption.AllDirectories))
    {
//.. process file
    }

在线程中,并在进程完成后触发事件