2008-09-17 93 views
3

我有一个经常更新(每分钟约20至30次)的.csv文件。我想在写入文件后立即将新添加的行插入到数据库中。使用.NET实时读取文件中的更改内容

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

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

回答

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 2014-11-05 11:54:23

0

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

然后请读者阅读您的最后一个文件大小,并从那里开始阅读。

+0

只是因为文件大小保持不变并不意味着没有任何改变。哈希会更合适..或在这种情况下,使用FileSystemWatcher。 – mmcdole 2008-10-19 15:27:13

1

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

2

对,FileSystemWatcher不知道任何关于您文件内容的信息。它会告诉你它是否改变了,等等,但没有改变。

你只是添加到文件?从帖子中可以看出,是否添加了线条或者是否可以删除。假设他们被追加,解决方案非常简单,否则你会做一些比较。

0

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

你有控制文件本身吗?您可以稍微改变模型以像缓冲区一样使用文件。有两个,而不是一个文件。一个是分期,一个是所有已处理产出的总和。读取“缓冲区”文件中的所有行,处理它们,然后将它们插入另一个文件的末尾,这是所有处理行的总数。然后,删除你处理的行。这样,文件中的所有信息都处于待处理状态。问题在于,如果系统是写入以外的东西(即也删除行),那么它将不起作用。

2

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

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

你可以找到一个description on TechNet。你将需要在.NET中使用PInvoke。