2010-10-21 16 views
6

Ho un file di testo contenente 21000 stringhe (una riga ciascuna) e 500 MB di altri file di testo (codici sorgente generici). Per ogni stringa ho bisogno di determinare se è contenuto in uno di questi file. Ho scritto un programma che fa il lavoro ma le sue prestazioni sono terribili (lo farei in un paio di giorni, ho bisogno di fare il lavoro in 5-6 ore al massimo).
Sto scrivendo utilizzando C#, Visual Studio 2010Ricerca di stringhe multiple in più file

Ho paio di domande riguardanti il ​​mio problema:
a) Quale approccio è migliore?

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

o

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

b) è meglio la scansione di una file riga per riga

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

o

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

c) Sarebbe threading migliorare le prestazioni e come fare quello?
d) Esiste un software in grado di farlo, quindi non devo scrivere il mio codice?

+0

devi scrivere il programma? windows ha findstr integrato. Puoi usare un ciclo for che possa cercare questi altri file in parallelo –

+0

Decisamente non una risposta corretta/completa, ma non caricare tutti i file (500 MB!) per ogni stringa. Una volta che hai (parte) il file in memoria, fai tutte le tue azioni allora. – Bertvan

+0

Suppongo di caricare l'intero file uno per uno, non 500 MB di file contemporaneamente. – Ichibann

risposta

3

Si desidera ridurre al minimo File I/O, quindi la prima idea è pessima perché si aprono gli "altri" file fino a 21.000 volte. Vuoi usare qualcosa in base al secondo (a1). E quando quegli altri file non sono eccessivamente grandi, caricali in memoria una volta con 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 parte di forza bruta può essere migliorata, ma penso che la troverai accettabile.

+0

È se (text.IndexOf (chiave)> = 0) più veloce di if (text.Contains (chiave))? – Ichibann

+0

@Ichi: No, mi aspetterei che fossero ugualmente veloci. –

2
  1. Sia a) e b), seconda opzione è efficace
  2. threading non può migliorare le prestazioni coz ogni thread leggerebbe il file dal disco, quindi il disco diventerà un collo di bottiglia.
  3. SRY non ho idea di s/w per il vostro scopo

frammento di filo

 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 

direttiva generale di I/O

Quello che segue sono alcune raccomandazioni di base per ridurre il Attività I/O del tuo programma, migliorando così le sue prestazioni. Come per tutte le raccomandazioni, è importante misurare le prestazioni del codice ottimizzato prima e dopo l'ottimizzazione per garantire che sia effettivamente più veloce.

  1. minimizzare il numero di file di operazioni si eseguono
  2. Gruppo diversi trasferimenti piccola di I/O in un unico grande trasferimento.Una singola scrittura di otto pagine è più veloce di otto scritture a pagina singola separate, principalmente perché consente al disco rigido di scrivere i dati in un passaggio sulla superficie del disco. Per ulteriori informazioni ,
  3. Eseguire letture sequenziali invece di cercare e leggere piccoli blocchi di dati . Il kernel in modo trasparente cluster operazioni di I/O, che rende letture sequenziali molto più veloce.
  4. Evitare di saltare in un file vuoto prima di scrivere i dati. Il sistema deve scrivere zeri nello spazio intermedio per riempire il vuoto. Per ulteriori informazioni, vedere Leggere è in genere più economico rispetto alla scrittura dei dati .
  5. Rinviare qualsiasi operazione di I/O fino al punto in cui l'applicazione in realtà richiede i dati.
  6. utilizzare il sistema di preferenze cattura solo le preferenze dell'utente (ad come posizioni di finestra e vista impostazioni) e non dati che possono essere ricalcolati economico.
  7. Non dare per scontato che i dati del file di cache in memoria acceleri l'applicazione . La memorizzazione dei dati dei file nella memoria migliora la velocità finché la memoria non viene trasferita su disco, al numero , che si paga il prezzo per l'accesso al disco ancora una volta. Sforzatevi di trovare un giusto equilibrio tra lettura dal disco e il caching in memoria
6

Se siete semplicemente desideroso di sapere se la stringa viene trovato o non trovato, e non hanno bisogno di fare alcun ulteriore trattamento, quindi ti suggerirei di usare solo grep. Grep è estremamente veloce e progettato proprio per questo tipo di problema.

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

dovrebbe fare il trucco. Sono sicuro che ci sia un'implementazione di Windows là fuori da qualche parte. Nel peggiore dei casi, Cygwin ce l'avrà.

EDIT: Questo risponde alla domanda d)

+0

Sì, nonostante il tag [C#] questo potrebbe essere l'approccio migliore. –

+0

Non ho familiarità con grep e come funziona, quindi forse un piccolo aiuto su come usarlo? – Ichibann

+0

Grep è uno strumento molto comune nei sistemi * nix. C'è molta documentazione là fuori, quindi ci sarà sicuramente un buon tutorial da qualche parte. Il comando suggerito cerca tutte le stringhe trovate in "stringhe-file" in uno qualsiasi degli "altri-file" e stampa tutte le linee corrispondenti in "altri-file". Ci sono molte opzioni per cambiare l'output in base alle tue esigenze. –

2

Fa la ricerca deve essere in tempo reale sulle attuali 500 MB di testo? Il motivo per cui lo chiedo è perché potresti creare un indice di ricerca sui file di testo ed eseguire la ricerca. Sarebbe molto più veloce ... Date un'occhiata a Lucene

Lucene.Net

C# and Lucene to index and search

+0

Non ha bisogno di essere la ricerca in tempo reale. È un compito una tantum. Fallo e dimenticalo: P – Ichibann

+0

Quindi usa Lucene (non ho usato Windows Search SDK) per creare un indice di ricerca completo ed eseguire ricerche contro di esso ... Ho usato Lucene prima ... È veloce! – zam6ak

Problemi correlati