2013-05-01 17 views
5

Voglio leggere periodicamente un file di registro che viene anche scritto. Il programma leggerà periodicamente il contenuto del file di registro e lo analizzerà per estrarre alcuni valori. Ma non voglio leggere l'intero file ogni volta.C# - Il modo più efficace di leggere periodicamente l'ultima parte di un file

C'è un modo per leggere un file da una particolare linea in poi?

Ad esempio alla prima lettura il file ha 100 righe. Prendo nota di questo valore e la prossima volta che leggo comincio a leggere dalla riga 100 in poi e memorizzo il numero di riga del file corrente.

Esiste un modo efficace per farlo? Il file di registro crescerà a circa 100 MB e ho bisogno di leggere circa ogni 5 secondi. Quindi non sarebbe così efficiente leggere il file completo ogni volta.

Qualsiasi suggerimento è molto apprezzato.

+2

Si potrebbe guardare Tail.NET http://www.codeproject.com/Articles/7568/Tail-NET – itsmatt

+0

Si potrebbe dividere il file in più file o di un DB destinato a tale scopo. Anche se, non sono sicuro di quanti benefici ci siano con solo 100 MB di file. Gli stream tendono ad avere indici iniziali. Perché non basta usarlo? –

risposta

3

Penso che stiate cercando questo, dove l'offset sarà quanto volete tornare indietro. Riferimento: MSDN

using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read)) 
{ 
    fs.Seek(offset, SeekOrigin.End); 
} 

Ora il filestream sta indicando comunque molto indietro nel file si imposta 'compensato' di essere, e si può leggere da lì.

+0

... hah, sono due minuti troppo lenti;) –

+0

@bland Grazie. Avrò un'occhiata a questo metodo. Sembra che questo potrebbe funzionare per me. – madu

2

Se il registro viene solo aggiunto, è possibile provare ad aprire un file in modalità di sola lettura senza blocco. In questo modo altri processi possono scriverlo mentre lo leggi.

var fs = new FileStream(path,FileMode.Open,FileAccess.Read, FileShare.ReadWrite); 
+0

Se ricordi la lunghezza del file, potresti essere in grado di "cercare" in quella posizione nella prossima lettura. – JosephHirn

1

Per qualcosa di veloce e sporco, lo uso. In questo caso si tratta di una discarica di registro - Non mi importa davvero di quante linee ho, voglio solo un mucchio alla fine (numBytes):

cmdLogReader = new System.IO.StreamReader(cmdLogFileIn); 

if (cmdLogReader.BaseStream.Length < (numBytes - 1)) { 
    return cmdLogReader.ReadToEnd; 
} else { 
    cmdLogReader.BaseStream.Seek(-numBytes, System.IO.SeekOrigin.End); 
    cmdLogReader.ReadLine(); 
    return cmdLogReader.ReadToEnd;   
} 

Si può sempre salvare il BaseStream.Length all'inizio e utilizzalo per calcolare fino a che punto la prossima volta (ovvero: numBytes diventa BaseStream.Length - previousBaseStreamLength o qualsiasi altra cosa), che consentirebbe alle chiamate sequenziali di afferrare tutto ciò che è stato aggiunto dall'ultima lettura.

Potrebbe essere necessario saltare la chiamata ReadLine se si esegue questa operazione poiché è davvero lì solo per spostarsi fino alla linea più vicina dopo aver fatto retrocedere un importo casuale. Se sai che stai per atterrare su un confine di linea, allora puoi solo ReadToEnd.

Questa è un'implementazione grintosa, ma è molto veloce ed è per questo che la utilizzo.

+0

Grazie. Non ero a conoscenza della proprietà BaseStream.Length e utilizzo di questo metodo per leggere il file. Osserverò questo metodo. – madu

1

Cercare può farlo bene. Ma voglio fornire altri passi avanti.

public static void Read() 
    { 
     var fs = new FileStream(@"G:\test.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 
     int lastReadCount = 0; 
     while (true) 
     { 
      var totalCountOfFile = fs.Length; 
      if (lastReadCount < totalCountOfFile) 
      { 
       var buffer = new byte[1024]; 
       int count = fs.Read(buffer, 0, buffer.Length); 
       lastReadCount += count; 
       Display(buffer); 
      } 
      Thread.Sleep(5000); 
     } 
    } 

    private static void Display(byte[] buffer) 
    { 
     var text = Encoding.UTF8.GetString(buffer.Where(p=>p != 0).ToArray()); 
     Console.Write(text); 
    }