2008-08-26 2 views
18

Есть ли способ найти количество файлов определенного типа без необходимости циклического преобразования всех результатов в каталог Directory.GetFiles() или аналогичный метод? Я ищу что-то вроде этого:Найти количество файлов с определенным расширением, во всех подкаталогах

int ComponentCount = MagicFindFileCount(@"c:\windows\system32", "*.dll"); 

Я знаю, что я могу сделать рекурсивную функцию для вызова Directory.GetFiles, но было бы гораздо чище, если бы я мог бы сделать это без всякой итерации.

EDIT: Если это невозможно сделать без повторения и повторения себя, какой был бы лучший способ сделать это?

ответ

31

Вы должны использовать перегрузку Directory.GetFiles(), используя Directory.GetFiles(path, searchPattern, SearchOption).

Путь указывает путь, searchPattern указывает ваши подстановочные знаки (например, *, * .format), а SearchOption предоставляет возможность включать подкаталоги.

Длина свойство обратной решетки этого поиска обеспечит надлежащее количество файлов для конкретного шаблона поиска и опции:

string[] files = directory.GetFiles(@"c:\windows\system32", "*.dll", SearchOption.AllDirectories); 

return files.Length; 

EDIT: В качестве альтернативы вы можете использовать Directory.EnumerateFiles method

return Directory.EnumerateFiles(@"c:\windows\system32", "*.dll", SearchOption.AllDirectories).Count(); 
+0

Это имеет массовый выпуск производительности с большим количеством файлов. – 2010-01-29 17:21:42

+0

@Aim - Можете ли вы (или кто-либо еще) количественно определить ваше заявление? Насколько медленной является «массовая производительность»? Сколько стоит «большое количество файлов»? Решение Jon работает для меня, но я хотел бы знать, когда/как это может стать проблематичным. – Dhaust 2010-08-19 04:13:14

+6

@DavidHAust Причина, заключающаяся в том, что метод `` GetFiles` (http://msdn.microsoft.com/en-us/library/07wt70x2.aspx) будет реализовывать * полный * список файлов, находящихся в каталоге. Предпочтительным способом вызова является [`Directory.EnumerateFiles`] (http://msdn.microsoft.com/en-us/library/dd383571.aspx), поскольку он будет передавать файлы обратно (через` yield`-like механизм), поскольку основной вызов ОС дает результаты обратно. – casperOne 2011-12-10 20:26:55

0

Кому-то нужно выполнить итерационную часть.

AFAIK, такого метода нет в .NET уже, поэтому я предполагаю, что кто-то должен быть вами.

6

Вы можете использовать эту перегрузку GetFiles:

Directory.GetFiles Method (String, String, SearchOption)

и этот член SearchOption:

AllDirectories - Включает текущий каталог и все подкаталоги в поисковой операции. Эта опция включает в себя точки повторной обработки, такие как установленные приводы и символические ссылки в поиске .

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

1

Использование рекурсии ваш MagicFindFileCount будет выглядеть следующим образом:

private int MagicFindFileCount(string strDirectory, string strFilter) { 
    int nFiles = Directory.GetFiles(strDirectory, strFilter).Length; 

    foreach(String dir in Directory.GetDirectories(strDirectory)) { 
     nFiles += GetNumberOfFiles(dir, strFilter); 
    } 

    return nFiles; 
    } 

Хотя Jon's solution может быть лучше.

6

Я искал более оптимизированную версию.Так как я не нашел его, я решил закодировать его и поделиться им здесь:

public static int GetFileCount(string path, string searchPattern, SearchOption searchOption) 
    { 
     var fileCount = 0; 
     var fileIter = Directory.EnumerateFiles(path, searchPattern, searchOption); 
     foreach (var file in fileIter) 
      fileCount++; 
     return fileCount; 
    } 

Все решения, использующие GetFiles/GetDirectories являются своего рода медленно, так как все эти объекты должны быть созданы. Используя перечисление, он не создает никаких временных объектов (FileInfo/DirectoryInfo).

см Примечания http://msdn.microsoft.com/en-us/library/dd383571.aspx для получения дополнительной информации

8

гладкий метод woud будет использовать LINQ:

var fileCount = (from file in Directory.EnumerateFiles(@"H:\iPod_Control\Music", "*.mp3", SearchOption.AllDirectories) 
        select file).Count(); 
1

У меня есть приложение, которое генерирует отсчеты каталогов и файлов в родительском каталоге. Некоторые из каталогов содержат тысячи подкаталогов с тысячами файлов в каждом. Чтобы сделать это, сохраняя отзывчивый пользовательский интерфейс, что я делаю следующее (отправка пути к ADirectoryPathWasSelected метода):

public class DirectoryFileCounter 
{ 
    int mDirectoriesToRead = 0; 

    // Pass this method the parent directory path 
    public void ADirectoryPathWasSelected(string path) 
    { 
     // create a task to do this in the background for responsive ui 
     // state is the path 
     Task.Factory.StartNew((state) => 
     { 
      try 
      { 
       // Get the first layer of sub directories 
       this.AddCountFilesAndFolders(state.ToString()) 


      } 
      catch // Add Handlers for exceptions 
      {} 
     }, path)); 
    } 

    // This method is called recursively 
    private void AddCountFilesAndFolders(string path) 
    { 
     try 
     { 
      // Only doing the top directory to prevent an exception from stopping the entire recursion 
      var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly); 

      // calling class is tracking the count of directories 
      this.mDirectoriesToRead += directories.Count(); 

      // get the child directories 
      // this uses an extension method to the IEnumerable<V> interface, 
      // which will run a function on an object. In this case 'd' is the 
      // collection of directories 
      directories.ActionOnEnumerable(d => AddCountFilesAndFolders(d)); 
     } 
     catch // Add Handlers for exceptions 
     { 
     } 
     try 
     { 
      // count the files in the directory 
      this.mFilesToRead += Directory.EnumerateFiles(path).Count(); 
     } 
     catch// Add Handlers for exceptions 
     { } 
    } 
} 
// Extension class 
public static class Extensions 
{ 
    // this runs the supplied method on each object in the supplied enumerable 
    public static void ActionOnEnumerable<V>(this IEnumerable<V> nodes,Action<V> doit) 
    { 

     foreach (var node in nodes) 
     { 
      doit(node); 
     } 
    } 
} 
Смежные вопросы