3

I have a .csv file that is frequently updated (about 20 to 30 times per minute). I want to insert the newly added lines to a database as soon as they are written to the file.

The FileSystemWatcher class listens to the file system change notifications and can raise an event whenever there is a change in a specified file. The problem is that the FileSystemWatcher cannot determine exactly which lines were added or removed (as far as I know).

One way to read those lines is to save and compare the line count between changes and read the difference between the last and second last change. However, I am looking for a cleaner (perhaps more elegant) solution.

4

6 に答える 6

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 );
                        }
                    }
                }
            }
        }
于 2008-09-17T19:47:08.037 に答える
2

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

ファイルに追加するだけですか?行が追加されたのか、それとも削除できるのかについて、投稿からは少し不明確でした. それらが追加されていると仮定すると、解決策は非常に簡単です。それ以外の場合は、いくつかの比較を行うことになります。

于 2008-09-17T19:23:24.600 に答える
2

NTFS Change Journal などを使用する必要があると思います。

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

説明は TechNet にあります。.NET で PInvoke を使用する必要があります。

于 2008-09-17T20:25:24.513 に答える
1

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

于 2008-09-17T19:21:12.997 に答える
0

頭のてっぺんから、最後の既知のファイルサイズを保存できます。ファイルサイズを確認し、ファイルサイズが変わったらリーダーを開きます。

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

于 2008-09-17T19:21:06.383 に答える
0

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

ファイル自体を制御できますか? モデルを少し変更して、ファイルをバッファーのように使用できます。1 つのファイルではなく、2 つのファイルを用意します。1 つはステージング、もう 1 つは処理されたすべての出力の合計です。「バッファ」ファイルからすべての行を読み取り、それらを処理してから、処理されたすべての行の合計である別のファイルの最後に挿入します。次に、処理した行を削除します。このようにして、ファイル内のすべての情報は処理が保留されます。問題は、システムが書き込み以外の場合 (つまり、行を削除する場合) は機能しないことです。

于 2008-09-17T19:23:37.097 に答える