2010-01-18 6 views
4

Mon application indexe le contenu de tous les disques durs sur les ordinateurs des utilisateurs finaux. J'utilise Directory.GetFiles et Directory.GetDirectories pour traiter récursivement toute la structure de dossiers. J'indexe seulement quelques types de fichiers sélectionnés (jusqu'à 10 types de fichiers). Je vois dans le profileur que la plus grande partie du temps d'indexation est consacrée à l'énumération des fichiers et des dossiers - en fonction du ratio de fichiers qui seront réellement indexés jusqu'à 90% du temps.Méthode rapide (lowlevel) pour traiter récursivement des fichiers dans des dossiers

Je voudrais faire l'indexation aussi vite que possible. J'ai déjà optimisé l'indexation et le traitement des fichiers indexés. Je pensais utiliser des appels d'API Win32, mais je vois actuellement dans le profileur que la plus grande partie du temps de traitement est réellement consacré à ces appels d'API effectués par .NET.

Existe-t-il une méthode (éventuellement de bas niveau) accessible à partir de C# qui rendrait l'énumération des fichiers/dossiers au moins partiellement plus rapide?


Comme demandé dans le commentaire, mon code actuel (juste un système avec des pièces non pertinentes coupé):

private IEnumerable<IndexedEntity> RecurseFolder(string indexedFolder) 
    { 
     //for a single extension: 
     string[] files = Directory.GetFiles(indexedFolder, extensionFilter); 
     foreach (string file in files) 
     { 
      yield return ProcessFile(file); 
     } 
     foreach (string directory in Directory.GetDirectories(indexedFolder)) 
     { 
      //recursively process all subdirectories 
      foreach (var ie in RecurseFolder(directory)) 
      { 
       yield return ie; 
      } 
     } 
    } 
+0

Cela vous dérange de partager le code que vous avez maintenant? – Bobby

+0

@Bobby: J'ai mis à jour la question – Marek

+0

Performance-sage, la "profondeur de l'API" n'a pas beaucoup d'importance. Le plus important est la stratégie récursive, lire/traiter tous les fichiers dans le répertoire courant avant d'aller dans les sous-dossiers (Mrk Gravell le comprend bien - en supposant que les appels GetFiles()/GetDirectories lisent tout, et l'appel GetDirectories est servi depuis le système de fichiers cache). – peterchen

Répondre

2

Dans .NET 4.0, il y a enumerable file listing methods intégré; puisque ce n'est pas loin, j'essaierais d'utiliser ça. Cela peut être un facteur en particulier si vous avez des dossiers qui sont massivement peuplés (nécessitant une grande allocation de tableau).

Si profondeur est la question, je considère aplatir votre méthode pour utiliser une pile locale/file d'attente et d'un seul blociterator. Cela permettra de réduire le chemin de code utilisé pour énumérer les dossiers profonds:

private static IEnumerable<string> WalkFiles(string path, string filter) 
    { 
     var pending = new Queue<string>(); 
     pending.Enqueue(path); 
     string[] tmp; 
     while (pending.Count > 0) 
     { 
      path = pending.Dequeue(); 
      tmp = Directory.GetFiles(path, filter); 
      for(int i = 0 ; i < tmp.Length ; i++) { 
       yield return tmp[i]; 
      } 
      tmp = Directory.GetDirectories(path); 
      for (int i = 0; i < tmp.Length; i++) { 
       pending.Enqueue(tmp[i]); 
      } 
     } 
    } 

Itérer que, en créant vos ProcessFile s à partir des résultats.

+1

Une chose à ajouter - attention aux points de reparse. Sinon, vous pourriez vous retrouver dans une récursion infinie. Pour un exemple, voir ici: http://weblogs.asp.net/israelio/archive/2004/06/23/162913.aspx – peterchen

+0

@peterchen - en effet; ils sont toujours amusants. –

+0

.NET 4.0 n'est pas une option pour moi, il s'agit d'une application .NET 2.0 – Marek

1

Si vous pensez que la mise en œuvre .NET est l'origine du problème alors je suggère que vous utilisez le winapi appelle _findfirst, _findnext etc.

Il me semble que .NET nécessite beaucoup de mémoire pour parce que les listes sont complètement copiés dans les tableaux à chaque niveau de répertoire - donc si votre structure de répertoires est profonde de 10 niveaux, vous avez 10 versions des fichiers de tableau à un moment donné et une allocation/désallocation de ce tableau pour chaque répertoire de la structure. L'utilisation de la même technique récursive avec _findfirst etc ne nécessite que des poignées à une position dans la structure de répertoires à chaque niveau de récursivité.

+0

Il n'y a pas de problème dans l'implémentation .NET, du moins pas dans mon cas. Je veux simplement faire ça plus vite. – Marek

+0

Je voulais dire que l'implémentation NET ralentissait l'exécution; causait un problème de performance. – Elemental

Questions connexes