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

Reading changes in a file in real-time using .NET

提问人: 提问时间:9/18/2008 最后编辑:3 revs, 2 users 95%Abbas 更新时间:10/13/2014 访问量:6893

问:

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

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

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

.net 文件 文件系统观察程序

评论


答:

0赞 expedient 9/18/2008 #1

在我的头顶上,您可以存储最后一个已知的文件大小。检查文件大小,当文件大小发生变化时,打开阅读器。

然后寻找阅读器到您最后的文件大小,然后从那里开始阅读。

评论

0赞 mmcdole 10/19/2008
仅仅因为文件大小保持不变并不意味着什么都没有改变。哈希会更合适。或者在本例中,使用 FileSystemWatcher。
1赞 James 9/18/2008 #2

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

2赞 itsmatt 9/18/2008 #3

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

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

0赞 Mike L 9/18/2008 #4

你对 FileSystemWatcher 的看法是对的。您可以侦听已创建、已修改、已删除等事件,但不会比引发这些事件的文件更深入。

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

3赞 RichS 9/18/2008 #5

我写过非常相似的东西。我使用 FileSystemWatcher 来获取有关更改的通知。然后,我使用 FileStream 来读取数据(跟踪我在文件中的最后一个位置,并在读取新数据之前寻找该位置)。然后,我将读取的数据添加到缓冲区中,该缓冲区会自动提取完整的行,然后输出到 UI。

注意:“这个。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 );
                        }
                    }
                }
            }
        }
2赞 artur02 9/18/2008 #6

我认为您应该使用 NTFS 更改日志或类似内容:

NTFS 使用更改日志来 提供所有 对卷上的文件所做的更改。 对于每个卷,NTFS 都使用更改 跟踪以下信息的日志 添加、删除和修改的文件。 变更日志远不止于此 比时间戳或文件更有效 用于确定更改的通知 在给定的命名空间中。

您可以在 TechNet 上找到说明。您需要在 .NET 中使用 PInvoke。