2008-08-26 12 views
18

¿Hay alguna manera de encontrar el número de archivos de un tipo específico sin tener que recorrer todos los resultados en un Directory.GetFiles() o método similar? Busco algo como esto:Buscar el número de archivos con una extensión específica, en todos los subdirectorios

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

sé que puedo hacer una función recursiva para llamar Directory.GetFiles, pero sería mucho más limpio si podía hacer esto sin toda la iteración.

EDITAR: Si no es posible hacer esto sin recurrir e iterar, ¿cuál sería la mejor manera de hacerlo?

Respuesta

31

Debe utilizar la sobrecarga Directory.GetFiles(path, searchPattern, SearchOption) de Directory.GetFiles().

La ruta especifica la ruta, searchPattern especifica sus comodines (por ejemplo, *, * .format) y SearchOption ofrece la opción de incluir subdirectorios.

La propiedad longitud de la matriz retorno de esta búsqueda proporcionará el número de archivos correcto para su patrón de búsqueda en particular y la opción:

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

return files.Length; 

EDIT: Alternativamente, puede utilizar Directory.EnumerateFiles method

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

Esto tiene un problema enorme rendimiento con gran número de archivos. –

+0

@Aim - ¿Puede usted (u otra persona) por favor, cuantificar su estado de cuenta? ¿Qué tan lento es el "problema de rendimiento masivo"? ¿Cuántos es "gran cantidad de archivos"? La solución de Jon funciona para mí, pero me gustaría saber cuándo y cómo podría ser problemático. – Dhaust

+6

@DavidHAust La razón es que [método 'GetFiles'] (http://msdn.microsoft.com/en-us/library/07wt70x2.aspx) se materializará la totalidad * * lista de los archivos que se encuentran en un directorio. El método preferido para llamar ahora es [ 'Directory.EnumerateFiles'] (http://msdn.microsoft.com/en-us/library/dd383571.aspx) ya que transmitir los archivos de nuevo (a través de un' yield'-como mecanismo) ya que la llamada subyacente al sistema operativo devuelve los resultados. – casperOne

0

Alguien tiene que hacer la parte iterativa.

AFAIK, no existe este método presente en .NET, así que supongo que alguien tiene que ser usted.

6

Puede utilizar esta sobrecarga de GetFiles:

Directory.GetFiles Method (String, String, SearchOption)

y este miembro de SearchOption:

AllDirectories - Incluye el directorio actual y todos los subdirectorios en una operación de búsqueda. Esta opción incluye puntos de análisis como unidades montadas y enlaces simbólicos en la búsqueda .

GetFiles devuelve una matriz de cadena para que pueda obtener la longitud que es el número de archivos encontrados.

1

El uso de la recursividad su MagicFindFileCount se vería así:

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; 
    } 

Aunque Jon's solution podría ser la mejor.

6

Estaba buscando una versión más optimizada.Ya que no he encontrado, me decidí a codificar y compartirlo aquí:

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; 
    } 

Todas las soluciones utilizando las GetFiles/GetDirectories son un poco lento ya que todos esos objetos necesitan ser creados. Usando la enumeración, no crea ningún objeto temporal (FileInfo/DirectoryInfo).

vea las observaciones http://msdn.microsoft.com/en-us/library/dd383571.aspx para más información

+1

yo siempre usar la extensión Enumerable.Count en esta situación ... ¿por qué no –

8

El método más hábil llenar de ser el uso de LINQ:

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

'Directory.EnumerateFiles (@ "H: \ iPod_Control \ Música", "* .mp3", SearchOption.AllDirectories) .Count()' – Firo

1

Tengo una aplicación que genera cargos de los directorios y archivos en un directorio padre. Algunos de los directorios contienen miles de subdirectorios con miles de archivos en cada uno. Para hacer esto mientras se mantiene una interfaz de usuario que responde hago lo siguiente (el envío de la ruta a ADirectoryPathWasSelected método):

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); 
     } 
    } 
} 
Cuestiones relacionadas