2010-10-21 3 views
6

J'ai un fichier texte contenant 21000 chaînes (une ligne chacune) et 500 Mo d'autres fichiers texte (codes sources maily). Pour chaque chaîne j'ai besoin de déterminer si elle est contenue dans l'un de ces fichiers. J'ai écrit un programme qui fait le travail mais sa performance est terrible (il le ferait dans quelques jours, j'ai besoin de faire le travail en 5-6 heures maximum).
J'écris en C#, Visual Studio 2010Recherche de plusieurs chaînes dans plusieurs fichiers

J'ai quelques questions concernant mon problème:
a) Quelle est la meilleure approche?

foreach(string s in StringsToSearch) 
{ 
    //scan all files and break when string is found 
} 

ou

foreach(string f in Files) 
{ 
    //search that file for each string that is not already found 
} 

b) Est-il préférable de balayer une ligne de fichiers en ligne

StreamReader r = new StreamReader(file); 
while(!r.EndOfStream) 
{ 
    string s = r.ReadLine(); 
    //... if(s.Contains(xxx)); 
} 

ou

StreamReader r = new StreamReader(file); 
string s = r.ReadToEnd(); 
//if(s.Contains(xxx)); 

c) Est-ce que le filetage d'améliorer les performances et comment pour faire ça?
d) Y a-t-il un logiciel qui peut le faire pour que je n'aie pas à écrire mon propre code?

+0

avez-vous d'écrire le programme? Windows a findstr intégré. Vous pouvez utiliser une boucle for qui pourrait rechercher ces autres fichiers en parallèle –

+0

Certainement pas une réponse correcte/complète, mais ne chargez pas tous les fichiers (500 Mo!) pour chaque chaîne. Une fois que vous avez (une partie de) le fichier en mémoire, faites alors toutes vos actions. – Bertvan

+0

Je souhaite charger un fichier entier un par un, pas 500 Mo de fichiers à la fois. – Ichibann

Répondre

3

Vous voulez minimiser les fichiers d'E/S, donc votre première idée est très mauvaise car vous ouvrez les 'autres' fichiers jusqu'à 21.000 fois. Vous voulez utiliser quelque chose basé sur le second (a1). Et quand ces autres fichiers ne sont pas trop grands, chargez-les en mémoire une fois avec readAllText.

List<string> keys = ...; // load all strings 

foreach(string f in Files) 
{ 
    //search for each string that is not already found 
    string text = System.IO.File.ReadAllText(f); //easy version of ReadToEnd 


    // brute force 
    foreach(string key in keyes) 
    { 
     if (text.IndexOf(key) >= 0) .... 
    } 

} 

La partie force brute peut être améliorée mais je pense que vous la trouverez acceptable.

+0

Est-ce que if (text.IndexOf (key)> = 0) est plus rapide que if (text.Contains (key))? – Ichibann

+0

@Ichi: Non, je m'attendrais à ce qu'ils soient aussi rapides. –

2
  1. Dans les deux cas a) et b), deuxième option est efficace
  2. filetage ne peut pas améliorer les performances coz chaque fil lirait le fichier à partir de votre disque, de sorte que votre disque deviendra un goulot d'étranglement.
  3. SRY je n'ai aucune idée de s/w pour votre but

extrait de fil

 foreach (FileInfo file in FileList) 
     { 
     Thread t = new Thread(new ParameterizedThreadStart(ProcessFileData)); 
     t.Start(file.FullName); 
     }//where processFileData is the method that process the files 

Directives générales I/O

Ce qui suit sont quelques recommandations de base pour réduire la Activité E/S de votre programme, améliorant ainsi ses performances. Comme pour toutes les recommandations, il est important de mesurer les performances du code en cours d'optimisation avant et après l'optimisation afin de s'assurer qu'il est réellement plus rapide.

  1. réduire le nombre de fichiers opérations que vous effectuez
  2. Groupe plusieurs petits Transferts E/S dans un grand transfert.Un seul écriture de huit pages est plus rapide que huit écritures d'une seule page distinctes, principalement parce qu'il permet au disque dur d'écrire les données en un seul passage sur la surface du disque. Pour plus d'informations ,
  3. Effectuer des lectures séquentielles au lieu de en recherchant et en lisant des petits blocs de données . Le noyau gère de manière transparente les opérations d'E/S, ce qui rend les lectures séquentielles beaucoup plus rapides.
  4. Évitez de faire un saut dans un fichier vide avant d'écrire des données. Le système doit écrire des zéros dans l'espace intermédiaire pour combler le vide. Pour plus d'informations, voir Lecture est généralement moins cher que l'écriture de données .
  5. Reporter toutes les opérations d'E/S jusqu'à ce que le indique que votre application a réellement besoin de ces données .
  6. Utilisez le système de préférences pour capture que les préférences des utilisateurs (tels que positions de fenêtre et vue paramètres) et non des données qui peuvent être à peu de frais recalculée.
  7. Ne supposez pas que la mise en cache des données de fichier en mémoire permettra d'accélérer votre application . Stocker des données de fichier dans la mémoire améliore la vitesse jusqu'à ce que la mémoire soit échangée sur le disque, à , ce qui signifie que vous payez le prix pour en accédant à nouveau au disque. Efforcez de trouver un équilibre approprié entre lecture à partir du disque et la mise en cache en mémoire
6

Si vous êtes désireux de savoir si la chaîne est trouvée, ou pas, et ne pas besoin de faire tout autre traitement, alors je vous suggère d'utiliser simplement grep. Grep est extrêmement rapide et conçu pour exactement ce genre de problème.

grep -f strings-file other-files... 

devrait faire l'affaire. Je suis sûr qu'il existe une implémentation Windows quelque part. Au pire, Cygwin l'aura.

EDIT: Cela répond à la question d)

+0

Oui, malgré la balise [C#], cela pourrait être la meilleure approche. –

+0

Je ne suis pas familier avec grep et comment cela fonctionne donc peut-être peu aider à l'utiliser? – Ichibann

+0

Grep est un outil très courant dans les systèmes * nix. Il y a beaucoup de documentation là-bas donc il y a forcément un bon tutoriel quelque part. La commande suggérée recherche toutes les chaînes trouvées dans "strings-file" dans l'un des "autres fichiers" et imprime toutes les lignes correspondantes dans "other-files". Il existe de nombreuses options pour modifier la sortie selon vos besoins. –

2

Est-ce que la recherche devra être temps réel sur 500 Mo de texte en cours? La raison pour laquelle je demande est parce que vous pourriez construire un index de recherche sur les fichiers texte et effectuer une recherche. Il serait beaucoup plus rapide ... Jetez un oeil à Lucene

Lucene.Net

C# and Lucene to index and search

+0

Il n'est pas nécessaire d'effectuer une recherche en temps réel. C'est une tâche ponctuelle. Faites-le et oubliez-le: P – Ichibann

+0

Ensuite, utilisez Lucene (je n'ai pas utilisé Windows Search SDK) pour construire un index de recherche complet et effectuer des recherches par rapport à cela ... J'ai utilisé Lucene avant ... C'est rapide! – zam6ak