2016-06-25 4 views
2

В этом методе, если я не ошибаюсь, он ищет внутри файлов. Итак, когда я набрал в searchTerm например «Form1», он нашел 46 файлов.Как я могу перебрать все файлы во всех каталогах и получить только типы файлов?

Но теперь я хочу изменить метод без searchTerm, чтобы он охватывал все файлы, но в конце я хочу получить список всех типов файлов. Если есть такой же дубликат, не добавляйте их в список, поэтому в конце я получу список с типами файлов, такими как: cs, txt, xml, поэтому я буду знать, какие типы файлов есть.

IEnumerable<string> SearchAccessibleFiles(string root, string searchTerm) 
     { 
      var files = new List<string>(); 

      foreach (var file in Directory.EnumerateFiles(root).Where(m => m.Contains(searchTerm))) 
      { 
       files.Add(file); 
      } 
      foreach (var subDir in Directory.EnumerateDirectories(root)) 
      { 
       try 
       { 
        files.AddRange(SearchAccessibleFiles(subDir, searchTerm)); 
       } 
       catch (UnauthorizedAccessException ex) 
       { 
        // ... 
       } 
      } 

      return files; 
     } 

Проблема заключается в том, что если я просто сделать GetFiles и корневой каталог C: \, то он остановится и не будет получать какие-либо файлы, когда он получает в каталог в окнах 10: Документы и настройки

Directory.GetFiles(textBox3.Text, "*.*", SearchOption.AllDirectories).ToList(); 

Поскольку я не нашел способ работать с Directory.GetFiles при переходе через этот каталог, я пытаюсь использовать рекурсивный метод.

ответ

1

Вы можете получить расширение файла с помощью extension = Path.GetExtension(fileName); и удалить дубликаты с помощью .Distinct() в списке файлов, как это:

IEnumerable<string> SearchAccessibleFiles(string root, string searchTerm) 
    { 
     var files = new List<string>(); 

     foreach (var file in Directory.EnumerateFiles(root).Where(m => m.Contains(searchTerm))) 
     { 
      string extension = Path.GetExtension(file); 
      files.Add(extension); 
     } 
     foreach (var subDir in Directory.EnumerateDirectories(root)) 
     { 
      try 
      { 
       files.AddRange(SearchAccessibleFiles(subDir, searchTerm)); 
      } 
      catch (UnauthorizedAccessException ex) 
      { 
       // ... 
      } 
     } 
     return files.Distinct().ToList(); 
    } 

вы можете просто удалить .Where(m => m.Contains(searchTerm)) часть для поиска без поиска.

Редактировать Если вы не хотите использовать .Distict() и хотите проверить дубликаты на ходу, вы можете попробовать этот метод:

IEnumerable<string> SearchAccessibleFilesNoDistinct(string root, List<string> files) 
{ 
    if(files == null) 
     files = new List<string>(); 

    foreach (var file in Directory.EnumerateFiles(root)) 
    { 
     string extension = Path.GetExtension(file); 
     if(!files.Containes(extension)) 
      files.Add(extension); 
    } 
    foreach (var subDir in Directory.EnumerateDirectories(root)) 
    { 
     try 
     { 
      SearchAccessibleFilesNoDistinct(subDir, files); 
     } 
     catch (UnauthorizedAccessException ex) 
     { 
      // ... 
     } 
    } 
    return files; 
} 

и первый раз вызов выглядит следующим образом:

var extensionsList = SearchAccessibleFilesNoDistinct("rootAddress",null); 

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

+0

Работает хорошо. Один вопрос, я добавил это, чтобы он не добавлял повторяющиеся расширения: if (! Files.Contains (extension)) непосредственно перед файлами строки .Add (расширение); но я все еще вижу дубликаты расширений в конце. Почему он продолжает добавлять дубликаты? –

+0

@ מנימנחם, это потому, что вы рекурсивно вызываете 'SearchAccessibleFiles', новый экземпляр списка' files', созданный каждый раз, когда вы вызываете 'SearchAccessibleFiles' в отношении области действия, и вы будете добавлять этот список usnig' files.AddRange' взамен. поэтому 'if (! files.Contains (extension))' принимает только дубликаты файлов внутри этого каталога, ни верхнюю директорию, ни дочернюю директорию. – hsh

+0

@ מנימנחם, вы поняли, где вы ошибаетесь? – hsh

1

Проблема может быть ломается до нескольких частей:

(1) Перечислить рекурсивно все доступные каталоги
(2) Перечислите несколько файлов каталога
(3) Получить особый файл расширений

Обратите внимание, что спецификация (3) является конкретной, (1) и (2) общей и может использоваться для другой обработки (например, ваш SearchAccessibleFiles и т. д.).Так что давайте решать их по отдельности:

(1) Перечислить рекурсивно все доступные каталоги:

Это, в свою очередь, может быть разделен на две части:

(A) Перечислить рекурсивно общей структуры дерева
(B) Специализация выше для доступного дерева каталогов

для (A) Я лично использую вспомогательный метод из моего ответа на How to flatten tree via LINQ? и аналогичные:

public static class TreeUtils 
{ 
    public static IEnumerable<T> Expand<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector) 
    { 
     var stack = new Stack<IEnumerator<T>>(); 
     var e = source.GetEnumerator(); 
     try 
     { 
      while (true) 
      { 
       while (e.MoveNext()) 
       { 
        var item = e.Current; 
        yield return item; 
        var elements = elementSelector(item); 
        if (elements == null) continue; 
        stack.Push(e); 
        e = elements.GetEnumerator(); 
       } 
       if (stack.Count == 0) break; 
       e.Dispose(); 
       e = stack.Pop(); 
      } 
     } 
     finally 
     { 
      e.Dispose(); 
      while (stack.Count != 0) stack.Pop().Dispose(); 
     } 
    } 
} 

и вот специализация для нашего случая:

public static partial class DirectoryUtils 
{ 
    public static IEnumerable<DirectoryInfo> EnumerateAccessibleDirectories(string path, bool all = false) 
    { 
     var filter = Func((IEnumerable<DirectoryInfo> source) => 
      source.Select(di => 
      { 
       try { return new { Info = di, Children = di.EnumerateDirectories() }; } 
       catch (UnauthorizedAccessException) { return null; } 
      }) 
      .Where(e => e != null)); 

     var items = filter(Enumerable.Repeat(new DirectoryInfo(path), 1)); 
     if (all) 
      items = items.Expand(e => filter(e.Children)); 
     else 
      items = items.Concat(items.SelectMany(e => filter(e.Children))); 
     return items.Select(e => e.Info); 
    } 

    static Func<T, TResult> Func<T, TResult>(Func<T, TResult> func) { return func; } 
} 

(2) Перечислите несколько файлов каталога:

А простые методы расширения для устранения повторяющихся код:

partial class DirectoryUtils 
{ 
    public static IEnumerable<FileInfo> EnumerateAccessibleFiles(string path, bool allDirectories = false) 
    { 
     return EnumerateAccessibleDirectories(path, allDirectories).EnumerateFiles(); 
    } 

    public static IEnumerable<FileInfo> EnumerateFiles(this IEnumerable<DirectoryInfo> source) 
    { 
     return source.SelectMany(di => di.EnumerateFiles()); 
    } 
} 

(3) Получить отдельные расширения файлов:

С выше хелперов, это вопрос простой LINQ запрос:

var result = DirectoryUtils.EnumerateAccessibleFiles(rootPath, true) 
    .Select(file => file.Extension).Distinct() 
    .ToList(); 

Наконец, просто для сравнения, вот как ваш оригинальный метод будет выглядеть при использовании тех же помощников:

IEnumerable<string> SearchAccessibleFiles(string root, string searchTerm) 
{ 
    return DirectoryUtils.EnumerateAccessibleFiles(rootPath, true) 
     .Where(file => file.FullName.Contains(searchTerm)) 
     .Select(file => file.FullName); 
} 

Если поисковый запрос не включает информацию о каталоге, вы можете изменить условие фильтра на file.Name.Contains(searchTerm).

Смежные вопросы