2008-09-17 14 views
3

頻繁に更新される.csvファイルがあります(毎分約20〜30回)。私は、ファイルに書き込まれるとすぐに、新しく追加された行をデータベースに挿入したいと思います。.NETでリアルタイムにファイルの変更を読み取る

FileSystemWatcherクラスはファイルシステムの変更通知をリッスンし、指定されたファイルに変更があるたびにイベントを発生させることができます。問題は、FileSystemWatcherが(私が知る限り)追加または削除された行を正確に判別できないことです。

これらの行を読み取る1つの方法は、変更の間の行数を保存して比較し、最後と最後の変更の差を読み取ることです。しかし、私はより洗練された(おそらくよりエレガントな)ソリューションを探しています。

答えて

3

私は非常に似たようなことを書いています。私は、FileSystemWatcherを使用して変更に関する通知を取得しました。その後、FileStreamを使用してデータを読み込みました(ファイル内の最後の位置を追跡し、新しいデータを読み込む前にそれを探します)。次に、読み込まれたデータをバッファに追加して、完全な行を自動的に抽出し、UIに出力します。

注:「this.MoreData(..)は、前述のバッファに追加し、完全なラインの抽出を扱うリスナーれたイベント、である

注:既に述べたように、これが唯一の意志変更が常にファイルに追加されていれば問題ありません。削除すると問題が発生します。

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

なぜdownvote? – RichS

0

私の頭の上から離れて、あなたは最後の既知のファイルサイズを保存することができます。ファイルサイズを確認し、変更されたらリーダーを開きます。

次に、最後のファイルサイズまでリーダーを探して、そこから読み始めます。

+0

ファイルサイズが同じであるという理由だけで、何も変更されていないというわけではありません。ハッシュははるかに適切です。この場合、FileSystemWatcherを使用してください。 – mmcdole

1

メモリが十分小さい場合は、現在のテキストをメモリに保存し、差分アルゴリズムを使用して新しいテキストと前のテキストが変更されたかどうかを確認します。このライブラリhttp://www.mathertel.de/Diff/は、何か変わっただけでなく、何が変わったかを伝えるだけでなく、したがって、変更されたデータをdbに挿入することができます。

2

右のFileSystemWatcherは、ファイルの内容について何も知らない。変更されたかどうかなどは教えられますが、何が変更されたかはわかりません。

ファイルに追加していますか?ラインが追加されたのか、削除されたのかについては、ポストから少し不明であった。それらが追加されていると仮定すると、解決策はかなり簡単です。そうでなければ、いくつかの比較を行います。

0

あなたはFileSystemWatcherについて正しくあります。作成、変更、削除などのイベントを聞くことができますが、それらを発生させたファイルよりも深くなることはありません。

ファイル自体を管理できますか?モデルを少し変更して、ファイルをバッファーのように使用することができます。 1つのファイルの代わりに、2つのファイルを持つ。 1つはステージングであり、1つは処理されたすべての出力の合計です。 "バッファ"ファイルからすべての行を読み込み、処理して、処理されたすべての行の合計である別のファイルの最後に挿入します。次に、処理した行を削除します。この方法では、ファイル内のすべての情報が処理待ちです。システムが書き込み以外のもの(つまり、行を削除する)であれば、それは機能しないということです。

2

は、私はあなたがNTFS変更ジャーナルまたは類似を使うべきだと思う:

変更ジャーナルは、ボリューム上のファイルに加えられたすべての 変更の永続的なログを提供 にNTFSで使用されます。 各ボリュームについて、NTFSは ジャーナルへのの変更情報を について追加、削除、および変更したファイルについて使用します。 変更ジャーナルは、タイムスタンプまたはファイル よりもはるかに効率的です。 変更を特定するための通知 は、指定された名前空間にあります。

description on TechNetがあります。 .NETでPInvokeを使用する必要があります。

関連する問題