使用.NET实时读取文件中的更改

时间:2008-09-17 19:12:58

标签: .net file filesystemwatcher

我有一个经常更新的.csv文件(大约每分钟20到30次)。我想在将新添加的行写入文件后立即将其插入数据库。

FileSystemWatcher类侦听文件系统更改通知,并且可以在指定文件发生更改时引发事件。问题是FileSystemWatcher无法确切地确定添加或删除了哪些行(据我所知)。

读取这些行的一种方法是保存和比较更改之间的行数,并读取最后一次和最后一次更改之间的差异。但是,我正在寻找一种更清洁(也许更优雅)的解决方案。

6 个答案:

答案 0 :(得分: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 );
                        }
                    }
                }
            }
        }

答案 1 :(得分:2)

是的,FileSystemWatcher对您文件的内容一无所知。它会告诉你它是否发生了变化等等,但不会发生变化。

您是否只是添加到文件中?从帖子中可以看出是否添加了线条还是可以删除线条。假设它们被追加,解决方案非常简单,否则你将进行一些比较。

答案 2 :(得分:2)

我认为你应该使用NTFS Change Journal或类似的东西:

  

NTFS使用更改日志   提供所有的持久日志   对卷上的文件所做的更改。   对于每个卷,NTFS使用更改   期刊跟踪有关的信息   添加,删除和修改文件。   变更日志更多   效率高于时间戳或文件   确定更改的通知   在给定的命名空间中。

您可以找到description on TechNet。您需要在.NET中使用PInvoke。

答案 3 :(得分:1)

如果它足够小,我会将当前文本保留在内存中,然后使用diff算法检查新文本和之前的文本是否已更改。这个库http://www.mathertel.de/Diff/不仅会告诉您某些内容已发生变化,而且还会发生变化。因此,您可以将更改的数据插入到数据库中。

答案 4 :(得分:0)

在我的头顶,你可以存储最后的已知文件大小。检查文件大小,更改时打开阅读器。

然后找读者的最后文件大小,并从那里开始阅读。

答案 5 :(得分:0)

你对FileSystemWatcher是正确的。您可以侦听已创建,已修改,已删除等事件,但不会比引发它们的文件更深入。

您是否可以控制文件本身?您可以稍微更改模型以将文件用作缓冲区。而不是一个文件,有两个。一个是分段,一个是所有已处理输出的总和。从“缓冲区”文件中读取所有行,处理它们,然后将它们插入到另一个文件的末尾,该文件是所有处理过的行的总和。然后,删除您处理的行。这样,文件中的所有信息都处于待处理状态。问题是如果系统不是写入(即也删除行),那么它将无法工作。