在问我Retrieve a list of filenames in folder and all subfolders quickly和我发现的其他一些问题中,搜索多个文件的方法似乎是使用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();
答案 0 :(得分: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();
你在评论中提到:
我想在列表中显示它们。并且完美地将它们发送到主要的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();
答案 1 :(得分: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);
}
});
答案 2 :(得分:4)
你可以做到
forach(var f in dir.EnumerateFiles("*.docx",SearchOption.AllDirectories))
{
//.. process file
}
在线程中,并在流程完成后触发事件