我有一个递归搜索,它在整个目录中搜索具有指定名称的文件。 这需要相当长的时间,我想显示一个进度条,它显示了至少一些进展(我不关心进度是否只是通过文件或目录的数量或它们的实际大小来衡量)。
以下(递归代码)执行搜索:
private void searchFolder(PortableDeviceFolder parent, ref List<PortableDeviceFolder> result, string filename)
{
foreach (var item in parent.Files)
{
if (item is PortableDeviceFolder)
{
searchFolder((PortableDeviceFolder)item, ref result, filenames);
}
else if ((String.Compare(item.Name, filename)==0))
{
result.Add(parent);
Console.WriteLine("Found file in: " + parent.Name);
}
}
}
我无法弄清楚如何取得进展。我在想一个简单的算法,它测量每个文件和文件夹的相同百分比;
等等。
不幸的是我无法在递归搜索中实现这一点。 有人有时间给我举个例子吗? 提前致谢
答案 0 :(得分:1)
评论者TaW建议您可以将要使用的目录计算为进度的基础。但这是一个小问题,不是建议本身,而是你的代码似乎实现的方式。
从您的问题中不清楚PortableDeviceFolder
是什么。但它似乎抽象了文件和文件夹之间的差异,从Files
属性返回。鉴于处理过程中最耗时的方面可能是实际检索给定目录的文件名,那么如果唯一的机制PortableDeviceFolder
必须返回给定目录中的目录,那么{{1}您必须最终枚举所有文件以及目录,忽略为生成计数而返回的文件。
换句话说,获取计数几乎与实际搜索给定名称一样长。
因此,为了这个答案的目的,我将假设Files
类有另一个属性PortableDeviceFolder
,它返回只是目录本身。有了这样的财产,我们就可以利用TaW提出的建议。
首先,你需要得到那个数。这样做的方法如下:
Folders
在显示任何进度之前会有一点延迟,因为当然没有有用的方法可以预测上述过程需要多长时间。但它应该相对简短,因为我们只关注目录而不是所有文件。
为了能够在处理过程中更新进度,我们应该在单独的线程中运行搜索,并使用private int CountFolders(PortableDeviceFolder rootFolder)
{
return rootFolder.Folders.Select(folder => CountFolders(folder)).Sum() + 1;
}
更新Dispatcher.Invoke()
属性。搜索方法如下所示:
ProgressBar.Value
注意:我不清楚为什么要通过引用传递private void SearchFolder(PortableDeviceFolder parent,
List<PortableDeviceFolder> result, string fileName, IProgress<int> progress)
{
foreach (var item in parent.Files)
{
PortableDeviceFolder folder = item as PortableDeviceFolder;
if (folder != null)
{
SearchFolder(folder, result, fileName, progress);
}
else if (item.Name.Equals(fileName, StringComparison.OrdinalIgnoreCase))
{
result.Add(parent);
}
}
progress.Report(1);
}
参数。这似乎并不需要,因此我将其更改为常规的按值参数。
在您的UI代码中,您可以这样称呼它:
result
请注意,我们在这里异步执行private async void SearchFolder_Click(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
button.IsEnabled = false;
string searchPath = textBlock1.Text, searchText = textBox1.Text;
List<PortableDeviceFolder> folders = new List<PortableDeviceFolder>();
PortableDeviceFolder rootFolder = new WindowsDirectoryFolder(searchPath);
progressBar1.Value = 0;
progressBar1.Maximum = await Task.Run(() => CountFolders(rootFolder));
Progress<int> progress =
new Progress<int>(increment => progressBar1.Value += increment);
await Task.Run(() => SearchFolder(rootFolder, folders, searchText, progress));
listBox1.ItemsSource = folders;
button.IsEnabled = true;
}
和CountFolders()
方法,以确保UI在工作完成时保持响应。
以上是我编写的一个简单的WPF程序来演示该技术,但它可以毫无困难地适应Winforms或其他GUI框架。基本思想保持不变。