BackgroundWorker&Timer,只读取日志文件的新行?

我的应用程序写入一个日志文件(目前使用log4net )。 我想设置一个计时器和一个后台工作程序来读取日志文件并将其内容打印到我的表单中的某个控件中,同时正在编写它。

我无法使用FileSystemWatcher类,因为它看起来很糟糕:有时事件“已更改”会触发,有时则不会。 它具有极低的“汇集率”。

所以我创建了一个Timer和一个FileSystemWatcher。 在计时器的“tick”事件中,后台工作人员完成其工作。

问题是: 如何只读取自上次检查工作人员以来添加的行?

public LogForm() { InitializeComponent(); logWatcherTimer.Start(); } private void logWatcherTimer_Tick(object sender, EventArgs e) { FileInfo log = new FileInfo(@"C:\log.txt"); if(!logWorker.IsBusy) logWorker.RunWorkerAsync(log); } private void logWorker_DoWork(object sender, DoWorkEventArgs e) { // Read only new lines since last check. FileInfo log = (FileInfo) e.Argument; // Here is the main question! } 

编辑:代码解决方案 (也许有更优雅的方式?):

 private void logWatherWorker_DoWork(object sender, DoWorkEventArgs e) { // retval string newLines = string.Empty; FileInfo log = (FileInfo) e.Argument; // Just skip if log file hasn't changed if (lastLogLength == log.Length) return; using (StreamReader stream = new StreamReader(log.FullName)) { // Set the position to the last log size and read // all the content added stream.BaseStream.Position = lastLogLength; newLines = stream.ReadToEnd(); } // Keep track of the previuos log length lastLogLength = log.Length; // Assign the result back to the worker, to be // consumed by the form e.Result = newLines; } 

每次阅读日志时检查并存储文件大小,然后在下次阅读时在该位置启动文本阅读器(或任何您正在使用的文件阅读器)。

您可以跟踪从流中读取的最后一个字符的索引,然后seek该位置。

编辑:请参阅http://dotnetperls.com/seek以获取示例。

如果您只想在表单上查看日志文件,那么为什么不做一些简单的事情,比如编写一个由TextBox,RichTextBox或其他任何东西支持的Appender。

以下是我发现只是快速谷歌搜索“log4net textbox appender”的一些链接:

http://www.nimblecoder.com/blog/archive/2009/01/30/using-a-delegate-and-custom-appender-with-log4net-to-display.aspx (这个看起来很酷,因为它允许你要指定一个委托来执行每条日志消息,所以你甚至不会被绑定到TextBox。你可以根据你希望日志输出去的地方编写不同的委托。

http://www.l4ndash.com/Log4NetMailArchive%2Ftabid%2F70%2Fforumid%2F1%2Fpostid%2F15133%2Fview%2Ftopic%2FDefault.aspx

http://weblogs.asp.net/psteele/archive/2010/01/25/live-capture-of-log4net-logging.aspx

http://www.l4ndash.com/Log4NetMailArchive%2Ftabid%2F70%2Fforumid%2F1%2Fpostid%2F14923%2Fview%2Ftopic%2FDefault.aspx (这是一个为每条记录的消息引发事件的Appender)。

http://markmail.org/message/ma62bdjpmab3cn7y (相对较新 – 2008年发布 – 使用RichTextBox生成ColoredConsoleAppender样式输出)

http://www.claassen.net/geek/blog/2005/06/log4net-scrollingtextbox.html (这个使用MemoryAppender捕获日志消息,然后将这些消息写入TextBox)

http://code.google.com/p/devdefined-tools/source/browse/trunk/projects/common/DevDefined.Common/Appenders/TextBoxAppender.cs?r=90

我没有尝试过这些,所以我不能保证它们的质量。 但是,我认为使用TextBox支持的自定义Appender的方法似乎比尝试查看日志文件,读取它,然后将消息放入TextBox更好。

在简要介绍这些Appender时我注意到的一些常见主题:

  1. 当您从Appender写入TextBox时,您可能需要使用BeginInvoke。

  2. 一个棘手的部分似乎是告诉Appender要写入哪个TextBox。 在大多数情况下,通过配置文件配置Appender,然后在日志记录系统初始化之后以编程方式将TextBox添加到Appender(我认为您必须至少检索一个记录器或记录至少一条消息以强制所有懒惰初始化的发生)。

  3. 要小心不断向TextBox添加行。 您可能会耗尽大量内存,导致性能问题或超出TextBox的限制(如果有的话)。 其中一些Appender包含定期从TextBox中删除“旧”行的代码。