none
Поиск файлов с System.IO.Directory.GetFiles (c#, WPF, VS 2010-2012) RRS feed

  • Вопрос

  • Здравствуйте.

    Произвожу поиск файлов по маске с использованием System.IO.Directory.GetFiles:

    string[] findFiles = System.IO.Directory.GetFiles(@"D:\Pictures", "*.jpg", System.IO.SearchOption.AllDirectories);

    Сталкнулся с такой проблемкой:

    1) Возможно ли как-нибудь производить поиск по нескольким маскам сразу (например сразу искать *.jpeg, *.jpg, *.png и т.д.)

    2) Как можно отобразить процесс поиска файлов (в каком каталоге идет поиск, сколько файлов обнаружено и т.д.)

    Заранее благодарю, Олег.

    15 марта 2013 г. 15:01

Ответы

  • Может кому-то пригодится... Из старых проектов:

        /// <summary>
        /// Предоставляет методы для поиска файлов в директории, включая вложенные.
        /// </summary>
        internal class FileWalker
        {
            #region Ctor
    
            /// <summary>
            /// Инициализирует новый экземпляр класса FileWalker.
            /// </summary>
            /// <param name="includePath">Список включаемых путей.</param>
            /// <param name="excludePath">Список исключаемых путей.</param>
            /// <param name="includeExtension">Список включаемых расширений.</param>
            /// <param name="excludeExtension">Список исключаемых расширений.</param>
            public FileWalker(IEnumerable<String> includePath, IEnumerable<String> excludePath, IEnumerable<String> includeExtension, IEnumerable<String> excludeExtension)
            {
                IncludePath = includePath;
                ExcludePath = excludePath;
                IncludeExtension = includeExtension;
                ExcludeExtension = excludeExtension;
            }
            
    #if DEBUG
            /// <summary>
            /// Полезен для обеспечения того, чтобы объекты должным образом были обработаны сборщиком мусора.
            /// </summary>
            ~FileWalker()
            {
                Debug.WriteLine(string.Format("{0} ({1}) Finalized", GetType().Name, GetHashCode()));
            }
    #endif
            
            #endregion
    
            #region Properties
    
            /// <summary>
            /// Возвращает или задает список включаемых путей.
            /// </summary>
            private IEnumerable<String> IncludePath { get; set; }
    
            /// <summary>
            /// Возвращает или задает список исключаемых путей.
            /// </summary>
            private IEnumerable<String> ExcludePath { get; set; }
    
            /// <summary>
            /// Возвращает или задает список включаемых расширений.
            /// </summary>
            private IEnumerable<String> IncludeExtension { get; set; }
    
            /// <summary>
            /// Возвращает или задает список исключаемых расширений.
            /// </summary>
            private IEnumerable<String> ExcludeExtension { get; set; }
    
            #endregion
    
            #region Public Members
    
            /// <summary>
            /// Возвращает имена файлов (включая пути) из указанного каталога.
            /// </summary>
            /// <returns>Массив String содержит имена файлов из указанного каталога.Имена файлов включают полный путь к файлу.</returns>
            public IEnumerable<String> GetFiles()
            {
                // Создаем список
                var list = new List<String>();
                // Проверяем список включаемых папок
                if (IncludePath != null)
                {
                    using (var enumerator = IncludePath.GetEnumerator())
                    {
                        // Проходим все пути
                        while (enumerator.MoveNext())
                        {
                            // Проверяем список строк поиска
                            if (IncludeExtension != null)
                            {
                                using (var iterator = IncludeExtension.GetEnumerator())
                                {
                                    // Проходим все строки поиска
                                    while (iterator.MoveNext())
                                    {
                                        // Проверяем папку в исключенных
                                        if (!ExcludePath.Contains(enumerator.Current, StringComparer.OrdinalIgnoreCase))
                                        {
                                            // Получаем файлы
                                            list.AddRange(GetFiles(enumerator.Current, iterator.Current));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                // Возвращаем результат
                return list;
            }
    
            #endregion
    
            #region Private Members
    
            /// <summary>
            /// Возвращает имена файлов (включая пути) из указанного каталога, отвечающие условиям заданного шаблона поиска.
            /// </summary>
            /// <param name="directory">Каталог, в котором необходимо выполнить поиск.</param>
            /// <param name="searchPattern">Строка поиска, которую необходимо сравнить с именами файлов, на которые указывает путь</param>
            /// <returns>Массив String содержит имена файлов из указанного каталога, отвечающие условиям заданного шаблона поиска.Имена файлов включают полный путь к файлу.</returns>
            private IEnumerable<String> GetFiles(String directory, String searchPattern)
            {
                // Создаем список
                var list = new List<String>();
                // Итератор по файлам
                using (var iterator = Directory.EnumerateFiles(directory, searchPattern).GetEnumerator())
                {
                    try
                    {
                        while (iterator.MoveNext())
                        {
                            // Получаем расширение файла и проверяем его
                            var fileInfo = new FileInfo(iterator.Current);
                            if (!ExcludeExtension.Contains(String.Concat("*", fileInfo.Extension)))
                            {
                                // Добавляем в список
                                list.Add(iterator.Current);
                            }
                        }
                    }
                    catch (ArgumentException ex)
                    {
                        // Путь является строкой нулевой длины, содержит только пробелы или содержит недопустимые символы.
                        // Параметр поиска не является допустимым значением.
                        Debug.Print(ex.Message);
                    }
                    catch (DirectoryNotFoundException ex)
                    {
                        // Путь недопустим, например, ссылается на неподключенный диск.
                        Debug.Print(ex.Message);
                    }
                    catch (IOException ex)
                    {
                        // Путь является именем файла.
                        // Длина указанного пути, имени файла или обоих параметров превышает установленный системой предел.
                        Debug.Print(ex.Message);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        // Исключение, возникающее в случае запрета доступа операционной системой 
                        // из-за ошибки ввода-вывода или особого типа ошибки безопасности.
                        Debug.Print(ex.Message);
                    }
                }
                // Итератор по директориям
                using (var iterator = Directory.EnumerateDirectories(directory).GetEnumerator())
                {
                    while (iterator.MoveNext())
                    {
                        try
                        {
                            // Проверяем папку в исключенных
                            if (!ExcludePath.Contains(iterator.Current, StringComparer.OrdinalIgnoreCase))
                            {
                                list.AddRange(GetFiles(iterator.Current, searchPattern));
                            }
                        }
                        catch (ArgumentException ex)
                        {
                            // Путь является строкой нулевой длины, содержит только пробелы или содержит недопустимые символы.
                            // Параметр поиска не является допустимым значением.
                            Debug.Print(ex.Message);
                        }
                        catch (DirectoryNotFoundException ex)
                        {
                            // Путь недопустим, например, ссылается на неподключенный диск.
                            Debug.Print(ex.Message);
                        }
                        catch (IOException ex)
                        {
                            // Путь является именем файла.
                            // Длина указанного пути, имени файла или обоих параметров превышает установленный системой предел.
                            Debug.Print(ex.Message);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            // Исключение, возникающее в случае запрета доступа операционной системой 
                            // из-за ошибки ввода-вывода или особого типа ошибки безопасности.
                            Debug.Print(ex.Message);
                        }
                    }
                }
                // Возвращаем результат
                return list;
            }
    
            #endregion
        }
    

    Комментарии я думаю исчерпывающие.


    • Изменено Kirill Bessonov 15 марта 2013 г. 19:40
    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 20:30
    • Снята пометка об ответе Hovanskiy 15 марта 2013 г. 20:58
    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 20:58
    15 марта 2013 г. 19:39
  • Изменил код под себя. Соответствует "Всем правилам Microsoft".

    private async void findFiles()
            {
                await Task.Run(() =>
                {
                    Action<string> addInListAction = (string text) =>
                    {
                        lb.Items.Add(text);
                        tb.Text = "В списке: " + lb.Items.Count.ToString();
                    };
                    SearchFilesInDirectory("D:\\", new List<string>() { "*.jpg", "*.png" }, addInListAction);
                });
            }
            /// <summary>
            /// Поиск файлов по маске
            /// </summary>
            /// <param name="directory">Директория, в которой осуществляется поиск</param>
            /// <param name="searchPatternList">
            /// Строка поиска, которую необходимо сравнивать с именами файлов в directory. Параметр 
            ///     не должен заканчиваться двумя точками ("..") или содержать две точки ("..") 
            ///     непосредственно перед System.IO.Path.DirectorySeparatorChar или System.IO.Path.AltDirectorySeparatorChar, 
            ///     а также не должен содержать символы, входящие в список System.IO.Path.InvalidPathChars.
            /// </param>
            /// <param name="method">Делегат метода, который принимает параметр типа System.String помещен в очередь событий System.Windows.Threading.Dispatcher.</param>
            /// <exception cref="ArgumentException">
            /// <para>Путь является строкой нулевой длины, содержит только пробелы или содержит недопустимые символы.</para>
            /// <para>Параметр поиска не является допустимым значением.</para>
            /// </exception>
            /// <exception cref="DirectoryNotFoundException">Путь недопустим, например, ссылается на неподключенный диск.</exception>
            /// <exception cref="IOException">
            /// <para>Путь является именем файла.</para>
            /// <para>Длина указанного пути, имени файла или обоих параметров превышает установленный системой предел.</para>
            /// </exception>
            /// <exception cref="UnauthorizedAccessException">Исключение, возникающее в случае запрета доступа операционной системой из-за 
            /// ошибки ввода-вывода или особого типа ошибки безопасности.</exception>
            /// <exception cref="ArgumentNullException">Исключение возникает, если параметр searchPatternList равен null или колличество элементов в нем равно 0.</exception>
            public void SearchFilesInDirectory(String directory, IEnumerable<string> searchPatternList, Delegate method)
            {
                if ((searchPatternList == null) || (searchPatternList.Count<string>() == 0))
                    throw new ArgumentNullException("searchPatternList");
                foreach (string searchPattern in searchPatternList)
                {
                    using (var iterator = Directory.EnumerateFiles(directory, searchPattern).GetEnumerator())
                    {
                        try
                        {
                            while (iterator.MoveNext())
                                Application.Current.Dispatcher.BeginInvoke(method, iterator.Current);
                        }
                        catch (ArgumentException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (DirectoryNotFoundException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (IOException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                    }
                }
                using (var iterator = Directory.EnumerateDirectories(directory).GetEnumerator())
                {
                    while (iterator.MoveNext())
                    {
                        try
                        {
                            SearchFilesInDirectory(iterator.Current, searchPatternList, method);
                        }
                        catch (ArgumentException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (DirectoryNotFoundException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (IOException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                    }
                }
            }

    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 20:42
    15 марта 2013 г. 20:42

Все ответы

  • 1. Я делаю отдельный запрос на каждый формат файла.

    2. Если использовать GetFiles, то отобразить прогресс не получится. MSDN советует на такой случай использовать EnumerateFiles. Соответственно запускаем его выполнение в отдельном потоке и реализуем поведение, которое будет передавать прогресс в основной поток (показывать текущую папку и т.д.)


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 16:18
    • Снята пометка об ответе Hovanskiy 15 марта 2013 г. 20:57
    15 марта 2013 г. 16:12
    Отвечающий
  • private void Search(string dir, string name)
    {
      string[] kyes = Directory.GetFiles(dir, name);
      foreach (var kye in kyes)
      {
        textBox1.Text += kye;
      }
    }
    Метод поиска файлов в заданном каталоге, предать путь к каталогу и расширения нужного для поиска файла, результат запишется в textBox.

    Нет. Это не то. Возможно я не правильно выразился - переформулирую:

    как делать выборку из списка найденных файлов я знаю, меня интересует есть ли возможность отобразить процесс наполнения списка!?

    15 марта 2013 г. 16:19
  • Спасибо. Но каким образом можно отловить/обработать момент нахождения и добавления файла в список в System.IO.Directory.EnumerateFiles ???

    Пока это все то же System.IO.Directory.GetFiles !?

    IEnumerable<string> findFiles = System.IO.Directory.EnumerateFiles(@"D:\Pictures", "*.jpg", System.IO.SearchOption.AllDirectories);
                foreach (string findFile in findFiles)
                    ListBox.Items.Add(findFile);
                TextBlock.Text = "Найдено файлов: " + findFiles.Count().ToString();

    • Изменено Hovanskiy 15 марта 2013 г. 16:29
    15 марта 2013 г. 16:27
  • Спасибо. Но каким образом можно отловить/обработать момент нахождения и добавления файла в список в System.IO.Directory.EnumerateFiles ???

    Пока это все то же System.IO.Directory.GetFiles !?

    IEnumerable<string> findFiles = System.IO.Directory.EnumerateFiles(@"D:\Pictures", "*.jpg", System.IO.SearchOption.AllDirectories);
                foreach (string findFile in findFiles)
                    ListBox.Items.Add(findFile);
                TextBlock.Text = "Найдено файлов: " + findFiles.Count().ToString();

    Никак нет. Например строка

     TextBlock.Text = "Найдено файлов: " + findFiles.Count().ToString();

    при GetFiles и EnumerateFiles будет иметь разный эффект. GetFiles вернет массив целиком, то есть если файлов много то именно строка с GetFiles будет висеть. Потом конечно вы можете пройти по массиву с помощью foreach, но момент зависания уже будет позади. EnumerateFiles же отрабатывает именно при foreach не получая весь массив ничего предварительно. Соответственно вы получаете истинный прогресс в реальном времени.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    15 марта 2013 г. 16:39
    Отвечающий
  • Да. Разобрался. Протормозил что-то.

    Вот мой метод:

    IEnumerable<string> files = from file in System.IO.Directory.EnumerateFiles(@"D:\Pictures\Картинки", "*.jpg", System.IO.SearchOption.AllDirectories) select fileж
                foreach (string file in files)
                    ListBox.Items.Add(file);
                TextBlock.Text = "Найдено файлов: " + files.Count<string>().ToString();

    И действительно в ListBox добавляет сразу как нашел!. Но как назло выскочила другая проблема:

    а как мне избавиться от скрытых файлов? (для каждого вызывать FileInfo ???)

    15 марта 2013 г. 16:46
  • Выходит, что да. По крайней мере в перегрузках EnumerateFiles таких возможностей нет.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 16:56
    • Снята пометка об ответе Hovanskiy 15 марта 2013 г. 20:57
    15 марта 2013 г. 16:52
    Отвечающий
  • ОК. Спасибо.
    15 марта 2013 г. 16:56
  • Блин. Поторопился.

    Не понял я все таки как работать с EnumerateFiles ???

    IEnumerable<string> files = from file in System.IO.Directory.EnumerateFiles(@"D:\Pictures\Картинки", "*.jpg", System.IO.SearchOption.AllDirectories) select fileж
                foreach (string file in files)
                    ListBox.Items.Add(file);
                TextBlock.Text = "Найдено файлов: " + files.Count<string>().ToString();

    Тут он сперва выводи все в files а уже потом я его обрабатываю - но это не то.

    Блин.

    15 марта 2013 г. 17:07
  • Ни как не могу взять в голову, чем отличается

     
    IEnumerable<string> files = from file in System.IO.Directory.EnumerateFiles(@"D:\Pictures\Картинки", "*.jpg", System.IO.SearchOption.AllDirectories) select file;
                foreach (string file in files)
                    ListBox.Items.Add(file);

    от

    string[] files = System.IO.Directory.GetFiles(@"D:\Pictures\Картинки", "*.jpg", System.IO.SearchOption.AllDirectories);
                foreach (string file in files)
                    lb.Items.Add(file);

    ????????????????????
    15 марта 2013 г. 17:29
  • Тут он сперва выводи все в files а уже потом я его обрабатываю - но это не то.
    А с чего вы это взяли? У меня EnumerateFiles отрабатывает как надо и files я получаю грубо говоря ссылку, а сама работа идет в foreach. Может дело в IEnumerable<string>? В примере для C# на стронице описания EnumerateFiles делают не так.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    15 марта 2013 г. 17:29
    Отвечающий
  • Если вы про это:

    var txtFiles = Directory.EnumerateFiles(sourceDirectory, "*.txt", SearchOption.AllDirectories);
    
                foreach (string currentFile in txtFiles)
                {
                    string fileName = currentFile.Substring(sourceDirectory.Length + 1);
                    Directory.Move(currentFile, Path.Combine(archiveDirectory, fileName));
                }

    То вся разница в том, что они просто не указывают тип, а используют var.

    Но если навести крысу на "EnumerateFiles" - в подсказке видно, что возвращаемый тип как раз IEnumerable<string>.

    15 марта 2013 г. 17:35
  • Если вы про это:

    var txtFiles = Directory.EnumerateFiles(sourceDirectory, "*.txt", SearchOption.AllDirectories);
    
                foreach (string currentFile in txtFiles)
                {
                    string fileName = currentFile.Substring(sourceDirectory.Length + 1);
                    Directory.Move(currentFile, Path.Combine(archiveDirectory, fileName));
                }

    То вся разница в том, что они просто не указывают тип, а используют var.

    Но если навести крысу на "EnumerateFiles" - в подсказке видно, что возвращаемый тип как раз IEnumerable<string>.

    Ок. С заморочками C# понятно. Теперь еще раз попробую. В

    var txtFiles = Directory.EnumerateFiles(sourceDirectory, "*.txt", SearchOption.AllDirectories);

    непосредственно операций с диском не происходит. Списка файлов в txtFiles на данном этапе нет.

    Когда же мы запускаем цикл происходит запрос к диску и возврат имен поочередно.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    15 марта 2013 г. 17:39
    Отвечающий
  • Я поставил точку остановка на строку сразу после EnumerateFiles. Как видите надпись "Расширение приведет к обработке коллекции" свидетельствует о том, что на данный момент она пуста, но если я нажму на + около "Результаты" то произойдет обработка коллекции и мы ее увидим.

    При использовании GetFiles в этой же точки останова коллекция уже будет наполнена.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 18:04
    • Снята пометка об ответе Hovanskiy 15 марта 2013 г. 20:57
    15 марта 2013 г. 17:45
    Отвечающий
  • Теперь понял. Спасибо. Просто раньше с там не сталкивался )).

    Реализовал сие чудо так:

    private async void findFiles()
            {
                await Task.Run(() =>
                {
                    Action<string> act = (string text) => { lb.Items.Add(text); tb.Text = "В списке: " + lb.Items.Count.ToString(); };
                    IEnumerable<string> files = from file in Directory.EnumerateFiles(@"D:\Pictures", "*.jpg", System.IO.SearchOption.AllDirectories) select file;
                    foreach (string file in files)
                        Application.Current.Dispatcher.BeginInvoke(act, file);
                });
            }

    Как вы считаете, это хороший код или нет!?

    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 18:04
    • Снята пометка об ответе Hovanskiy 15 марта 2013 г. 20:57
    15 марта 2013 г. 17:52
  • Как вы считаете, это хороший код или нет!?
    Ну насколько мне хватает знаний в C#, да это хороший код. Даже при очень большом объеме файлов вы будете не повесите интерфейс и будете видеть добавление файлов в реальном времени.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    15 марта 2013 г. 17:56
    Отвечающий
  • А что вы понимаете под "хорошим"? Чтобы он выглядел устрошающе с использованием делегатов, новых примочек C# 5.0, и обобщений. И новички охали при виде такого кода. Если серьёзно, работает как нужно - значит хороший.
    15 марта 2013 г. 18:00
    Модератор
  • Можно еще один нубовский вопрос!? :)

    А как мне быть с запретом на доступ к файлам? Если я указываю путь типа C:\ или D:\ естественно стабильно натыкаюсь на папку к которой у меня нет доступа. Как мне наплевать на нее и продолжить поиск???

    Пытался обработать исключение UnauthorizedAccessException через try/catch, но при его возбуждении цикл прекращается.

    15 марта 2013 г. 18:03
  • А что вы понимаете под "хорошим"? Чтобы он выглядел устрошающе с использованием делегатов, новых примочек C# 5.0, и обобщений. И новички охали при виде такого кода. Если серьёзно, работает как нужно - значит хороший.

    Я имею ввиду не красоту кода (хотя это наверное тоже не маловажно), а именно надежность, скорость выполнения и стабильность.
    15 марта 2013 г. 18:10
  • Пытался обработать исключение UnauthorizedAccessException через try/catch, но при его возбуждении цикл прекращается.

    Я сейчас тоже работаю над приложением, в котором пользователю предлагается выбрать папку с фото и решаю задачу так же как вы. Соответственно когда цикл прерывается я выдаю сообщение, что размещение недопустимое и прошу выбрать более "детальный" путь к фото.

    Альтернативой я вижу, только собственную рекурсивную функцию с решением всех потенциальных проблем, но меня устраивает и мое текущее решение.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    15 марта 2013 г. 18:11
    Отвечающий
  • А как вообще узнать имею ли я право открыть папку или нет? Ни как не могу ума дать.

    В интернете полно вариантов с использованием "DirectorySecurity ds = dir.GetAccessControl(AccessControlSections.Access);"

    Но если сделать, к примеру, так, то все равно вечно выскакивает исключение о доступе:

    string[] dirs = Directory.GetDirectories(@"D:\");
                Console.WriteLine("Найденно {0} папок", dirs.Length.ToString());
                foreach (string findDir in dirs)
                {
                    var di = new DirectoryInfo(findDir);
                    foreach (DirectoryInfo dir in di.GetDirectories())
                    {
                        DirectorySecurity ds = dir.GetAccessControl(AccessControlSections.Access);
                        foreach (FileSystemAccessRule fsar in ds.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)))
                        {
                            if (fsar.FileSystemRights == FileSystemRights.ListDirectory)
                                Console.WriteLine("Доступ к папке {0} разрешен", dir);
                        }
                    }
                }

    • Изменено Hovanskiy 15 марта 2013 г. 19:07
    15 марта 2013 г. 18:56
  • Может кому-то пригодится... Из старых проектов:

        /// <summary>
        /// Предоставляет методы для поиска файлов в директории, включая вложенные.
        /// </summary>
        internal class FileWalker
        {
            #region Ctor
    
            /// <summary>
            /// Инициализирует новый экземпляр класса FileWalker.
            /// </summary>
            /// <param name="includePath">Список включаемых путей.</param>
            /// <param name="excludePath">Список исключаемых путей.</param>
            /// <param name="includeExtension">Список включаемых расширений.</param>
            /// <param name="excludeExtension">Список исключаемых расширений.</param>
            public FileWalker(IEnumerable<String> includePath, IEnumerable<String> excludePath, IEnumerable<String> includeExtension, IEnumerable<String> excludeExtension)
            {
                IncludePath = includePath;
                ExcludePath = excludePath;
                IncludeExtension = includeExtension;
                ExcludeExtension = excludeExtension;
            }
            
    #if DEBUG
            /// <summary>
            /// Полезен для обеспечения того, чтобы объекты должным образом были обработаны сборщиком мусора.
            /// </summary>
            ~FileWalker()
            {
                Debug.WriteLine(string.Format("{0} ({1}) Finalized", GetType().Name, GetHashCode()));
            }
    #endif
            
            #endregion
    
            #region Properties
    
            /// <summary>
            /// Возвращает или задает список включаемых путей.
            /// </summary>
            private IEnumerable<String> IncludePath { get; set; }
    
            /// <summary>
            /// Возвращает или задает список исключаемых путей.
            /// </summary>
            private IEnumerable<String> ExcludePath { get; set; }
    
            /// <summary>
            /// Возвращает или задает список включаемых расширений.
            /// </summary>
            private IEnumerable<String> IncludeExtension { get; set; }
    
            /// <summary>
            /// Возвращает или задает список исключаемых расширений.
            /// </summary>
            private IEnumerable<String> ExcludeExtension { get; set; }
    
            #endregion
    
            #region Public Members
    
            /// <summary>
            /// Возвращает имена файлов (включая пути) из указанного каталога.
            /// </summary>
            /// <returns>Массив String содержит имена файлов из указанного каталога.Имена файлов включают полный путь к файлу.</returns>
            public IEnumerable<String> GetFiles()
            {
                // Создаем список
                var list = new List<String>();
                // Проверяем список включаемых папок
                if (IncludePath != null)
                {
                    using (var enumerator = IncludePath.GetEnumerator())
                    {
                        // Проходим все пути
                        while (enumerator.MoveNext())
                        {
                            // Проверяем список строк поиска
                            if (IncludeExtension != null)
                            {
                                using (var iterator = IncludeExtension.GetEnumerator())
                                {
                                    // Проходим все строки поиска
                                    while (iterator.MoveNext())
                                    {
                                        // Проверяем папку в исключенных
                                        if (!ExcludePath.Contains(enumerator.Current, StringComparer.OrdinalIgnoreCase))
                                        {
                                            // Получаем файлы
                                            list.AddRange(GetFiles(enumerator.Current, iterator.Current));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                // Возвращаем результат
                return list;
            }
    
            #endregion
    
            #region Private Members
    
            /// <summary>
            /// Возвращает имена файлов (включая пути) из указанного каталога, отвечающие условиям заданного шаблона поиска.
            /// </summary>
            /// <param name="directory">Каталог, в котором необходимо выполнить поиск.</param>
            /// <param name="searchPattern">Строка поиска, которую необходимо сравнить с именами файлов, на которые указывает путь</param>
            /// <returns>Массив String содержит имена файлов из указанного каталога, отвечающие условиям заданного шаблона поиска.Имена файлов включают полный путь к файлу.</returns>
            private IEnumerable<String> GetFiles(String directory, String searchPattern)
            {
                // Создаем список
                var list = new List<String>();
                // Итератор по файлам
                using (var iterator = Directory.EnumerateFiles(directory, searchPattern).GetEnumerator())
                {
                    try
                    {
                        while (iterator.MoveNext())
                        {
                            // Получаем расширение файла и проверяем его
                            var fileInfo = new FileInfo(iterator.Current);
                            if (!ExcludeExtension.Contains(String.Concat("*", fileInfo.Extension)))
                            {
                                // Добавляем в список
                                list.Add(iterator.Current);
                            }
                        }
                    }
                    catch (ArgumentException ex)
                    {
                        // Путь является строкой нулевой длины, содержит только пробелы или содержит недопустимые символы.
                        // Параметр поиска не является допустимым значением.
                        Debug.Print(ex.Message);
                    }
                    catch (DirectoryNotFoundException ex)
                    {
                        // Путь недопустим, например, ссылается на неподключенный диск.
                        Debug.Print(ex.Message);
                    }
                    catch (IOException ex)
                    {
                        // Путь является именем файла.
                        // Длина указанного пути, имени файла или обоих параметров превышает установленный системой предел.
                        Debug.Print(ex.Message);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        // Исключение, возникающее в случае запрета доступа операционной системой 
                        // из-за ошибки ввода-вывода или особого типа ошибки безопасности.
                        Debug.Print(ex.Message);
                    }
                }
                // Итератор по директориям
                using (var iterator = Directory.EnumerateDirectories(directory).GetEnumerator())
                {
                    while (iterator.MoveNext())
                    {
                        try
                        {
                            // Проверяем папку в исключенных
                            if (!ExcludePath.Contains(iterator.Current, StringComparer.OrdinalIgnoreCase))
                            {
                                list.AddRange(GetFiles(iterator.Current, searchPattern));
                            }
                        }
                        catch (ArgumentException ex)
                        {
                            // Путь является строкой нулевой длины, содержит только пробелы или содержит недопустимые символы.
                            // Параметр поиска не является допустимым значением.
                            Debug.Print(ex.Message);
                        }
                        catch (DirectoryNotFoundException ex)
                        {
                            // Путь недопустим, например, ссылается на неподключенный диск.
                            Debug.Print(ex.Message);
                        }
                        catch (IOException ex)
                        {
                            // Путь является именем файла.
                            // Длина указанного пути, имени файла или обоих параметров превышает установленный системой предел.
                            Debug.Print(ex.Message);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            // Исключение, возникающее в случае запрета доступа операционной системой 
                            // из-за ошибки ввода-вывода или особого типа ошибки безопасности.
                            Debug.Print(ex.Message);
                        }
                    }
                }
                // Возвращаем результат
                return list;
            }
    
            #endregion
        }
    

    Комментарии я думаю исчерпывающие.


    • Изменено Kirill Bessonov 15 марта 2013 г. 19:40
    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 20:30
    • Снята пометка об ответе Hovanskiy 15 марта 2013 г. 20:58
    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 20:58
    15 марта 2013 г. 19:39
  • Интересная реализация.

    Во всяком случае работает.

    Но надо немного изменить...


    Спасибо за код. Действительно было полезно почитать. Раньше никогда не имел дело с "Debug.Print...". Теперь приму на вооружение.
    • Изменено Hovanskiy 15 марта 2013 г. 20:45 Оценил
    15 марта 2013 г. 19:46
  •     class Program
        {
            static void Main(string[] args)
            {
                var fileWalker = new FileWalker(new[] { @"C:\Windows" }, new[] { @"C:\Windows\System32" }, new[] { "*.jpeg", "*.jpg", "*.png" }, new string[0]);
                int count = 0;
                foreach(var file in fileWalker.GetFiles())
                {
                    count++;
                    Console.WriteLine(file);
                }
                Console.WriteLine("Всего: {0}", count);
            }
        }
    

    15 марта 2013 г. 20:04
  • Возможно немножко подпилить нужно...
    15 марта 2013 г. 20:06
  • Изменил код под себя. Соответствует "Всем правилам Microsoft".

    private async void findFiles()
            {
                await Task.Run(() =>
                {
                    Action<string> addInListAction = (string text) =>
                    {
                        lb.Items.Add(text);
                        tb.Text = "В списке: " + lb.Items.Count.ToString();
                    };
                    SearchFilesInDirectory("D:\\", new List<string>() { "*.jpg", "*.png" }, addInListAction);
                });
            }
            /// <summary>
            /// Поиск файлов по маске
            /// </summary>
            /// <param name="directory">Директория, в которой осуществляется поиск</param>
            /// <param name="searchPatternList">
            /// Строка поиска, которую необходимо сравнивать с именами файлов в directory. Параметр 
            ///     не должен заканчиваться двумя точками ("..") или содержать две точки ("..") 
            ///     непосредственно перед System.IO.Path.DirectorySeparatorChar или System.IO.Path.AltDirectorySeparatorChar, 
            ///     а также не должен содержать символы, входящие в список System.IO.Path.InvalidPathChars.
            /// </param>
            /// <param name="method">Делегат метода, который принимает параметр типа System.String помещен в очередь событий System.Windows.Threading.Dispatcher.</param>
            /// <exception cref="ArgumentException">
            /// <para>Путь является строкой нулевой длины, содержит только пробелы или содержит недопустимые символы.</para>
            /// <para>Параметр поиска не является допустимым значением.</para>
            /// </exception>
            /// <exception cref="DirectoryNotFoundException">Путь недопустим, например, ссылается на неподключенный диск.</exception>
            /// <exception cref="IOException">
            /// <para>Путь является именем файла.</para>
            /// <para>Длина указанного пути, имени файла или обоих параметров превышает установленный системой предел.</para>
            /// </exception>
            /// <exception cref="UnauthorizedAccessException">Исключение, возникающее в случае запрета доступа операционной системой из-за 
            /// ошибки ввода-вывода или особого типа ошибки безопасности.</exception>
            /// <exception cref="ArgumentNullException">Исключение возникает, если параметр searchPatternList равен null или колличество элементов в нем равно 0.</exception>
            public void SearchFilesInDirectory(String directory, IEnumerable<string> searchPatternList, Delegate method)
            {
                if ((searchPatternList == null) || (searchPatternList.Count<string>() == 0))
                    throw new ArgumentNullException("searchPatternList");
                foreach (string searchPattern in searchPatternList)
                {
                    using (var iterator = Directory.EnumerateFiles(directory, searchPattern).GetEnumerator())
                    {
                        try
                        {
                            while (iterator.MoveNext())
                                Application.Current.Dispatcher.BeginInvoke(method, iterator.Current);
                        }
                        catch (ArgumentException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (DirectoryNotFoundException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (IOException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                    }
                }
                using (var iterator = Directory.EnumerateDirectories(directory).GetEnumerator())
                {
                    while (iterator.MoveNext())
                    {
                        try
                        {
                            SearchFilesInDirectory(iterator.Current, searchPatternList, method);
                        }
                        catch (ArgumentException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (DirectoryNotFoundException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (IOException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            Debug.Print(ex.Message);
                        }
                    }
                }
            }

    • Помечено в качестве ответа Hovanskiy 15 марта 2013 г. 20:42
    15 марта 2013 г. 20:42
  • Ну и, конечно же, в лучших традициях решения проблемы - возник новый вопрос! ))

    А как отследить завершение поиска??? К примеру выдать сообщение "Усе! Нашел все что было!".

    15 марта 2013 г. 20:52
  • Так когда у вас выполнение асинхронной функции findFiles закончится (можно к примеру вернуть Task<bool>), так и выводите.

    var result = await findFiles();

    Debug.WriteLine("Усе! Нашел все что было!");

    15 марта 2013 г. 21:16
  • Так когда у вас выполнение асинхронной функции findFiles закончится (можно к примеру вернуть Task<bool>), так и выводите.

    var result = await findFiles();

    Debug.WriteLine("Усе! Нашел все что было!");


    А можно наглядный пример реализации???
    P.S. И не подскажите ли как можно прервать выполнение асинхронного метода? (Отправить поиску команду "Стой! Отмена!")
    • Изменено Hovanskiy 15 марта 2013 г. 21:41
    15 марта 2013 г. 21:34
  •         private async void Search()
            {
                await findFiles();
    
                Console.WriteLine("Усе! Нашел все что было!");
            }
    
            private async Task findFiles()
            {
                await Task.Run(() =>
                {
                    Action<string> addInListAction = (string text) =>
                    {
                        lb.Items.Add(text);
                        tb.Text = "В списке: " + lb.Items.Count.ToString();
                    };
                    SearchFilesInDirectory("D:\\", new List<string>() { "*.jpg", "*.png" }, addInListAction);
                });
            }
    Можно даже без всяких возвращений bool.


    15 марта 2013 г. 21:50
  • Делаю так:

    private async void mAddFileInFolder_Click(object sender, RoutedEventArgs e)
            {
                // ...
                await SearchImagesFiles(FBD);
                MessageBox.Show("Find end");
                // ...
            }
    
    private async Task SearchImagesFiles(System.Windows.Forms.FolderBrowserDialog FBD)
    // ...
    Но сообщение выскакивает сразу!
    15 марта 2013 г. 21:58