BackgroundWorker&定时器,只读取日志文件的新行?

时间:2010-11-30 21:00:11

标签: c# timer log4net backgroundworker filesystemwatcher

我的应用程序写入日志文件(当前使用 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;
}

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

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

修改:有关示例,请参阅http://dotnetperls.com/seek

答案 2 :(得分:2)

如果您只想在表单上查看表单上的日志文件,为什么不做一些简单的事情,比如写一个由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中删除“旧”行的代码。