【问题标题】:Reading changes in a file in real-time using .NET使用 .NET 实时读取文件中的更改
【发布时间】:2008-09-17 19:12:58
【问题描述】:

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

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

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

【问题讨论】:

    标签: .net file filesystemwatcher


    【解决方案1】:

    我写过一些非常相似的东西。我使用 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 );
                            }
                        }
                    }
                }
            }
    

    【讨论】:

      【解决方案2】:

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

      您只是添加到文件中吗?帖子中关于是否添加或也可以删除行有点不清楚。假设它们已附加,则解决方案非常简单,否则您将进行一些比较。

      【讨论】:

        【解决方案3】:

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

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

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

        【讨论】:

          【解决方案4】:

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

          【讨论】:

            【解决方案5】:

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

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

            【讨论】:

            • 文件大小保持不变并不意味着没有任何变化。散列会更合适.. 或者在这种情况下,使用 FileSystemWatcher。
            【解决方案6】:

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

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

            【讨论】:

              猜你喜欢
              • 2011-01-23
              • 2021-09-10
              • 1970-01-01
              • 2012-06-28
              • 1970-01-01
              • 1970-01-01
              • 2012-12-02
              • 2011-08-16
              • 1970-01-01
              相关资源
              最近更新 更多