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!
}

EDIT: Code Solution (может быть, есть более элегантный способ?):

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;
}

Ответ 1

Проверяйте и сохраняйте размер файла каждый раз, когда вы читаете журнал, затем запустите свой текстовый ридер (или что-то еще, что вы используете) в этом месте при следующем чтении.

Ответ 2

Вы можете отслеживать индекс последнего символа, считываемого из потока, а затем seek в эту позицию.

Изменить: см. http://dotnetperls.com/seek для примеров.

Ответ 3

Если вы хотите просмотреть файл журнала в форме, когда он написан, почему бы не сделать что-то простое, например написать собственный Appender, который поддерживается TextBox, RichTextBox или что-то еще.

Вот некоторые ссылки, которые я нашел, просто выполняя быстрый поиск Google для "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

Я не пробовал ни одного из них, поэтому я не могу ручаться за их качество. Но я думаю, что подход использования пользовательского Appender, поддерживаемого TextBox, кажется гораздо более удобным, чем попытка просмотра файла журнала, его чтения, а затем размещения сообщений в текстовом поле.

Некоторые общие темы, которые я заметил, глядя кратко на этих Appenders:

  • Когда вы пишете в TextBox из Appender, вам может потребоваться использовать BeginInvoke.

  • Кажется, что одна сложная часть говорит Appender, который TextBox пишет. В большинстве случаев Appender настраивается через файл конфигурации, а затем TextBox добавляется в Appender программно ПОСЛЕ того, как система протоколирования была инициализирована (я думаю, вам нужно либо получить хотя бы один регистратор, либо записать хотя бы одно сообщение, чтобы заставить все от ленивой инициализации).

  • Будьте осторожны, постоянно добавляя строки в TextBox. Вы можете использовать много памяти, вызывать проблемы с производительностью или превышать лимит на TextBox (если таковой имеется). Некоторые из этих Appenders включают код, который периодически удаляет "старые" строки из TextBox.