【问题标题】:Is there a way to stop a Directory.GetFiles search有没有办法停止 Directory.GetFiles 搜索
【发布时间】:2017-10-22 15:26:15
【问题描述】:

我正在使用Directory.GetFiles() 搜索多文件夹目录中的文件,其中一些文件夹太大,因此搜索可能需要长达 60 秒。在下面的代码中,搜索在用户停止输入后一秒钟开始,当用户输入文件名并且在输入时不暂停时,这非常有效,但如果他/她在单词中间暂停,搜索将开始并会即使他/她再次开始打字,也不会停止直到它完成。

我想做的是在用户输入时停止搜索,可能在 inputFileName_TextChanged 方法中。

使用Directory.GetFiles时,有没有办法停止已经开始的搜索?

using System.Timers;
using System.IO;

namespace findFileTest
{

    public partial class MainWindow : Window
    {
        Timer timer = new Timer();

        public MainWindow()
        {
            InitializeComponent();

            timer.Elapsed += new ElapsedEventHandler(TimerEvent);
            timer.Interval = 1000;
            timer.Enabled = true;
            timer.Stop();
        }

        private void inputFileName_TextChanged(object sender, TextChangedEventArgs e)
        {
            // How to stop the search currently in process here
            timer.Stop();
            timer.Start();
        }

        public void TimerEvent(object source, ElapsedEventArgs e)
        {
            timer.Stop();
            findFile();
        }

        private void findFile()
        {
            string fName = "";

            this.Dispatcher.Invoke(() => {
                fName = inputFileName.Text;
            });

            var fType = ".txt";
            var fileName = fName.Trim() + fType;

            var file = Directory.GetFiles(@"C:\TestFolder\", fileName, SearchOption.AllDirectories).FirstOrDefault();
            if (file == null) {
                Console.WriteLine("File not found");
            }
            else {
                Console.WriteLine("Found:" + file);
            }
        }
    }
}

【问题讨论】:

  • 方法错误,Directory.EnumerateFiles() 很容易停止。只需 break 退出 foreach 循环即可。

标签: c# directory getfiles


【解决方案1】:

有没有办法在使用 Directory.GetFiles 时停止已经开始的搜索?

不,不安全。 GetFiles() 方法没有提供任何机制来在它返回之前中断它的工作。您将不得不中止线程,这会导致许多其他问题。

正如this comment 中所述,从字面上理解您的请求,答案将是使用Directory.EnumerateFiles() 方法。此方法通过提供一次返回一个文件的枚举器来显示底层FindFirstFile()FindNextFile() 的语义。每次返回一个新文件时,您都有机会中断枚举并返回而无需做更多工作。

请注意,即使使用EnumerateFiles(),在找到与您的搜索模式匹配的内容之前,您也不会获得第一个文件结果。如果您切换到使用EnumerateFiles(),您可能还想对输入进行自己的匹配,而不是让EnumerateFiles() 进行匹配。 IE。传递"*" 作为搜索字符串。这会稍微减慢整体操作,但您将有机会中断搜索目录和子目录中每个文件的操作,而不是仅在找到匹配文件时。 p>

最后,我建议鉴于您的明显用例,您可能需要重新考虑使用 Directory 类。根据您发布的代码,您正在启动对文件系统的搜索,这是一个必然很慢的操作,每次用户输入一些新文本时。恕我直言,最好建立一次索引(例如,将不带扩展名的文件名(即Path.GetFileNameWithoutExtension())映射到目录中每个匹配文件的完整路径的Dictionary<string, List<string>>)。这样,您就不必中断任何事情。用户输入文本后的“搜索”部分几乎是瞬间完成的。

在目录被完全索引之前当然会有一个初始延迟。这取决于你想如何处理它。但我建议提供一种机制,既可以向用户指示索引未完全完成,又可以检查您拥有的内容,以防用户正在查找的文件与已编入索引的文件匹配。

请注意,常用的 Windows 文件系统(FAT、FAT32、NTFS 等)不区分大小写,因此您需要使用StringComparer.OrdinalIgnoreCase 来初始化您的字典。 “Ordinal”,因为文件系统名称需要与用户键入的确切字符匹配,并且“忽略大小写”以便搜索不区分大小写。

我猜在您的场景中,当用户使用您的程序搜索文件时,不太可能添加或删除文件。但是,如果您担心这种情况,您可以只为用户提供“刷新”按钮以强制重新索引目录,或者在添加或删除文件时使用FileSystemWatcher 自动更新索引。

【讨论】:

  • @Peter Duniho 在你的前两段中,你回答了我关于为什么使用Directory.EnumerateFiles() 而不是Directory.GetFile() 的问题,谢谢。建立索引的想法听起来非常好,但听起来我有点复杂,但我一定会研究它。快速的问题,索引文件通常是如何处理的,你得到字典列表然后你保存它以便以后引用它?
  • 是的。 List<string> 是给定名称的所有文件名的完整路径列表。例如。如果您有三个目录,每个目录都有一个名为“foo.txt”的文件,那么您的字典将在“foo”键下有一个包含这三个文件的完整路径的列表。建立索引时,您需要使用TryGetValue() 来查看密钥是否已经存在;如果是,则只需将找到的新文件添加到该键的列表中,如果不是,则首先创建列表,将其添加为该键的值,然后将新文件添加到新列表中。
  • 这开始有意义了,不带扩展名的文件名将是键,路径将是List 中的值。现在,由于一旦完成第一个索引,大多数请求将通过List 而不是通过搜索完成,List 的大小是否有限制?谢谢。
  • "大部分请求将通过列表完成" -- 如果您正在构建和使用索引,则所有搜索都应通过索引。 “List 的大小是否有限制?” -- 所有的计算机都是有限的机器,所以是的……有一个限制。但是List<T> 类使用一个数组作为其底层存储,而.NET 数组的大小可以为 2GB。所以,虽然有一个限制,但这个限制远比你可能需要的要大得多。如果你确实超出了这个限制,你只需要一个更复杂的数据结构(例如字典值的列表列表)。
猜你喜欢
  • 2013-12-25
  • 1970-01-01
  • 2017-04-02
  • 2012-10-17
  • 1970-01-01
  • 2021-01-14
  • 1970-01-01
  • 1970-01-01
  • 2019-09-27
相关资源
最近更新 更多