2009-04-03 17 views
17

Tengo un trabajo que se ejecuta todas las noches para extraer archivos xml de un directorio que tiene más de 20,000 subcarpetas en la raíz. Esto es lo que ve la estructura como:La manera más rápida en C# para encontrar un archivo en un directorio con más de 20,000 archivos

rootFolder/someFolder/someSubFolder/xml/myFile.xml 
rootFolder/someFolder/someSubFolder1/xml/myFile1.xml 
rootFolder/someFolder/someSubFolderN/xml/myFile2.xml 
rootFolder/someFolder1 
rootFolder/someFolderN 

Así que mirar lo anterior, la estructura es siempre la misma - una carpeta raíz, a continuación, dos subcarpetas, a continuación, un directorio xml, y luego el archivo XML. Solo conozco el nombre de rootFolder y el directorio xml.

El siguiente código atraviesa todos los directorios y es extremadamente lento. ¿Alguna recomendación sobre cómo puedo optimizar la búsqueda, especialmente si se conoce la estructura del directorio?

string[] files = Directory.GetFiles(@"\\somenetworkpath\rootFolder", "*.xml", SearchOption.AllDirectories); 
+0

¿Está buscando un archivo xml particular o desea una lista de todos ellos? –

+0

Estoy buscando todos los archivos xml – adeel825

+0

Si la lista de archivos xml no cambia con el tiempo, podría compilar la lista una sola vez y leer todos los archivos de la lista. Pero probablemente lo sabías. – Bearddo

Respuesta

15

En lugar de hacer GetFiles y hacer una búsqueda de fuerza bruta, lo más probable es utilizar GetDirectories, primero para obtener una lista de la "Primera subcarpeta", recorrer esos directorios, luego repetir el proceso para la subcarpeta, recorriendo ellos, finalmente busque la carpeta xml, y finalmente busque archivos .xml.

Ahora, en cuanto a rendimiento, la velocidad de esto variará, pero primero buscar directorios, ¡ENTONCES llegar a los archivos debería ayudar mucho!

actualización

Ok, lo hice un poco rápido de la prueba y en realidad se puede optimizar mucho más lejos de lo que pensaba.

El siguiente fragmento de código buscará en una estructura de directorios y encontrará TODAS las carpetas "xml" dentro de todo el árbol de directorios.

string startPath = @"C:\Testing\Testing\bin\Debug"; 
string[] oDirectories = Directory.GetDirectories(startPath, "xml", SearchOption.AllDirectories); 
Console.WriteLine(oDirectories.Length.ToString()); 
foreach (string oCurrent in oDirectories) 
    Console.WriteLine(oCurrent); 
Console.ReadLine(); 

Si deja caer que en una aplicación de consola de prueba, verá que los resultados de salida.

Ahora, una vez que tenga esto, simplemente busque en cada uno de los directorios encontrados los archivos .xml.

3

¿Hay directorios adicionales en el mismo nivel que la carpeta xml? Si es así, probablemente podría acelerar la búsqueda si lo hace usted mismo y eliminar ese nivel de búsqueda.

 System.IO.DirectoryInfo root = new System.IO.DirectoryInfo(rootPath); 
     List<System.IO.FileInfo> xmlFiles=new List<System.IO.FileInfo>(); 

     foreach (System.IO.DirectoryInfo subDir1 in root.GetDirectories()) 
     { 
      foreach (System.IO.DirectoryInfo subDir2 in subDir1.GetDirectories()) 
      { 
       System.IO.DirectoryInfo xmlDir = new System.IO.DirectoryInfo(System.IO.Path.Combine(subDir2.FullName, "xml")); 

       if (xmlDir.Exists) 
       { 
        xmlFiles.AddRange(xmlDir.GetFiles("*.xml")); 
       } 
      } 
     } 
0

No se me ocurre nada más rápido en C#, pero ¿tiene indexado encendido para ese sistema de archivos?

+0

La indexación no debería hacer mucho por simple recorrido. – Joey

0

La única forma que veo que marcaría una gran diferencia es cambiar de una búsqueda de fuerza bruta y usar alguna rutina de indexación de terceros o OS para acelerar el retorno. de esa manera, la búsqueda se realiza fuera de línea desde su aplicación.

Pero también le sugiero que busque mejores formas de estructurar esos datos si es posible.

0

Use P/Invoke en FindFirstFile/FindNextFile/FindClose y evite la sobrecarga de crear muchas instancias de FileInfo.

Pero esto será un trabajo difícil para hacerlo bien (tendrá que hacer todo el manejo del archivo contra el directorio y la recursión por su cuenta). Intente algo simple (Directory.GetFiles(), Directory.GetDirectories()) para comenzar y hacer que las cosas funcionen. Si es demasiado lento, mire las alternativas (pero siempre mida, demasiado fácil para hacerlo más lento).

+0

¿Conoces algún contenedor FindFirstFile/FindNextFile/FindClose para .net que actúa como un IEnumerable? –

+1

@ DanielMošmondor 'Systen, IO.Directoey' ahora tiene tales métodos (agregados en .NET 4). P.ej. ['EnumerateDirectories'] (http://msdn.microsoft.com/en-us/library/dd383304.aspx). – Richard

+0

No es algo de lo que estoy orgulloso, pero todavía estoy en .net 2 :) –

6

he creado un método recursivo GetFolders utilizando un Parallel.ForEach para encontrar todas las carpetas con el nombre como la variable yourKeyword

List<string> returnFolders = new List<string>(); 
object locker = new object(); 

Parallel.ForEach(subFolders, subFolder => 
{ 
    if (subFolder.ToUpper().EndsWith(yourKeyword)) 
    { 
     lock (locker) 
     { 
      returnFolders.Add(subFolder); 
     } 
    } 
    else 
    { 
     lock (locker) 
     { 
      returnFolders.AddRange(GetFolders(Directory.GetDirectories(subFolder))); 
     } 
    } 
}); 

return returnFolders; 
Cuestiones relacionadas