2008-09-17 4 views
3

Ich habe eine .csv-Datei, die häufig aktualisiert wird (etwa 20 bis 30 Mal pro Minute). Ich möchte die neu hinzugefügten Zeilen in eine Datenbank einfügen, sobald sie in die Datei geschrieben werden.Lesen von Änderungen in einer Datei in Echtzeit mit .NET

Die Klasse FileSystemWatcher überwacht die Benachrichtigungen zu Dateisystemänderungen und kann bei jeder Änderung einer bestimmten Datei ein Ereignis auslösen. Das Problem ist, dass der FileSystemWatcher nicht genau bestimmen kann, welche Zeilen hinzugefügt oder entfernt wurden (soweit ich weiß).

Eine Möglichkeit, diese Zeilen zu lesen, besteht darin, die Zeilenanzahl zwischen den Änderungen zu speichern und zu vergleichen und den Unterschied zwischen der letzten und der zweitletzten Änderung zu lesen. Ich suche jedoch eine sauberere (vielleicht elegantere) Lösung.

Antwort

3

Ich habe etwas sehr ähnliches geschrieben. Ich habe den FileSystemWatcher verwendet, um Benachrichtigungen über Änderungen zu erhalten. Ich benutzte dann einen FileStream, um die Daten zu lesen (meine letzte Position in der Datei zu verfolgen und danach zu suchen, bevor die neuen Daten gelesen wurden). Dann füge ich die gelesenen Daten zu einem Puffer hinzu, der automatisch komplette Linien extrahiert und dann dann zur UI ausgibt.

Hinweis: „this.MoreData (..) ist ein Ereignis, der Zuhörer, von denen den oben genannten Puffer ergänzt und übernimmt die komplette Linie Extraktion

. Hinweis: Wie bereits erwähnt, wird dies nur funktionieren, wenn die Änderungen immer zu der Datei hinzugefügt werden.Jede Löschung führt zu Problemen.

Hoffe, das hilft.

public void File_Changed(object source, FileSystemEventArgs e) 
    { 
     lock (this) 
     { 
      if (!this.bPaused) 
      { 
       bool bMoreData = false; 

       // Read from current seek position to end of file 
       byte[] bytesRead = new byte[this.iMaxBytes]; 
       FileStream fs = new FileStream(this.strFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 

       if (0 == this.iPreviousSeekPos) 
       { 
        if (this.bReadFromStart) 
        { 
         if (null != this.BeginReadStart) 
         { 
          this.BeginReadStart(null, null); 
         } 
         this.bReadingFromStart = true; 
        } 
        else 
        { 
         if (fs.Length > this.iMaxBytes) 
         { 
          this.iPreviousSeekPos = fs.Length - this.iMaxBytes; 
         } 
        } 
       } 

       this.iPreviousSeekPos = (int)fs.Seek(this.iPreviousSeekPos, SeekOrigin.Begin); 
       int iNumBytes = fs.Read(bytesRead, 0, this.iMaxBytes); 
       this.iPreviousSeekPos += iNumBytes; 

       // If we haven't read all the data, then raise another event 
       if (this.iPreviousSeekPos < fs.Length) 
       { 
        bMoreData = true; 
       } 

       fs.Close(); 

       string strData = this.encoding.GetString(bytesRead); 
       this.MoreData(this, strData); 

       if (bMoreData) 
       { 
        File_Changed(null, null); 
       } 
       else 
       { 
        if (this.bReadingFromStart) 
        { 
         this.bReadingFromStart = false; 
         if (null != this.EndReadStart) 
         { 
          this.EndReadStart(null, null); 
         } 
        } 
       } 
      } 
     } 
+0

Warum der Downvote? – RichS

0

von meinem Kopf entfernt, könnten Sie die letzte bekannte Dateigröße speichern. Überprüfen Sie anhand der Dateigröße, und wenn es sich ändert, öffnen Sie einen Leser.

Dann suchen Sie den Leser auf Ihre letzte Dateigröße und beginnen Sie von dort zu lesen.

+0

Nur weil die Dateigröße gleich bleibt, heißt das nicht, dass sich nichts geändert hat. Ein Hash wäre viel geeigneter .. oder in diesem Fall mit FileSystemWatcher. – mmcdole

1

Ich würde den aktuellen Text im Speicher behalten, wenn er klein genug ist, und dann einen Diff-Algorithmus verwenden, um zu prüfen, ob sich der neue Text und der vorherige Text geändert haben. Diese Bibliothek, http://www.mathertel.de/Diff/, wird Ihnen nicht nur sagen, dass sich etwas geändert hat, sondern auch, was sich geändert hat. Sie können dann die geänderten Daten in die Datenbank einfügen.

2

Richtig, der FileSystemWatcher weiß nichts über den Inhalt Ihrer Datei. Es wird dir sagen, ob es sich geändert hat usw., aber nicht was sich geändert hat.

Fügen Sie nur der Datei hinzu? Es war von der Post ein wenig unklar, ob Linien hinzugefügt wurden oder auch entfernt werden konnten. Unter der Annahme, dass sie angehängt sind, ist die Lösung ziemlich einfach, sonst werden Sie einige Vergleiche anstellen.

0

Sie haben Recht mit dem FileSystemWatcher. Sie können nach erstellten, geänderten, gelöschten usw. Ereignissen suchen, aber Sie kommen nicht tiefer als die Datei, die sie ausgelöst hat.

Haben Sie die Kontrolle über die Datei selbst? Sie könnten das Modell leicht ändern, um die Datei wie einen Puffer zu verwenden. Statt einer Datei zwei haben. Einer ist die Inszenierung, einer ist die Summe aller verarbeiteten Ausgaben. Lesen Sie alle Zeilen aus Ihrer "Puffer" -Datei, verarbeiten Sie sie und fügen Sie sie am Ende einer anderen Datei ein, die die Summe aller verarbeiteten Zeilen darstellt. Löschen Sie dann die von Ihnen verarbeiteten Zeilen. Auf diese Weise werden alle Informationen in Ihrer Datei verarbeitet. Der Catch ist, dass, wenn das System etwas anderes als write ist (d. H. Auch Zeilen löscht), es nicht funktioniert.

2

Ich glaube, Sie NTFS Change Journal oder ähnliches verwenden sollen:

Das Änderungsjournal wird von NTFS zu bietet ein persistentes Protokoll aller Änderungen an Dateien auf dem Datenträger verwendet. Für jedes Volume verwendet NTFS die Änderung Journal zu verfolgen Informationen über hinzugefügt, gelöscht und modifizierte Dateien. Die Änderung Journal ist viel mehr effizienter als Zeitstempel oder Datei Benachrichtigungen zum Ermitteln von Änderungen in einem bestimmten Namespace.

Sie können eine description on TechNet finden. Sie müssen PInvoke in .NET verwenden.

Verwandte Themen