如何监视文本文件并在文本框中连续输出内容

时间:2012-03-18 08:32:31

标签: c#

我正在制作一个控制游戏服务器的程序。我正在做的一个功能是实时服务器日志文件监视器。

有一个日志文件(一个简单的文本文件),在运行时由服务器更新。

如何连续检查日志文件并在RichTextBox中输出内容?

我做了这个简单的功能只是尝试获取日志的内容。 它当然会逐行获取文本并将其输出到我的文本框中。 它也会在循环运行时锁定程序,所以我知道它没用。

public void ReadLog()
{
  using (StreamReader reader = new StreamReader("server.log"))
  {
    String line;

    // Read and display lines from the file until the end of the file is reached.
    while ((line = reader.ReadLine()) != null)
    {
      monitorTextBox.AppendText(line + "\n");
      CursorDown();
    }
  }
}

但是,您如何尽可能简单地解决实时监控?

*编辑*

我正在使用Prescots解决方案。好东西。

目前我正在使用sstreamreader将文件中的文本放到我的文本框中。我遇到的问题是,每当我试图访问我的事件处理程序中的任何gui控件时,程序就会停止而没有错误或警告。

我发现它与线程有关。我解决了这个问题:

private void OnChanged(object source, FileSystemEventArgs e)
{
    if (monitorTextField.InvokeRequired)
    {
        monitorTextField.Invoke((MethodInvoker)delegate { OnChanged(source, e); });
    }
    else
    {
      StreamReader reader = new StreamReader("file.txt");

      monitorTextField.Text = "";
      monitorTextField.Text = reader.ReadToEnd();
      reader.Close();
      CursorDown();
    }
}

现在我唯一的问题是服务器使用了file.txt,所以我无法访问它,因为它“被另一个进程使用”。我无法控制这个过程..所以也许我运气不好。

但是当serevr运行时,文件可以在记事本中打开,所以不管怎么说它必须是可能的。也许我可以在更新和读取副本时对文件进行临时复制。说不上...

5 个答案:

答案 0 :(得分:14)

查看System.IO.FileSystemWatcher课程:

public static Watch() 
{
    var watch = new FileSystemWatcher();
    watch.Path = @"D:\tmp";
    watch.Filter = "file.txt";
    watch.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite; //more options
    watch.Changed += new FileSystemEventHandler(OnChanged);
    watch.EnableRaisingEvents = true;
}

/// Functions:
private static void OnChanged(object source, FileSystemEventArgs e)
{
    if(e.FullPath == @"D:\tmp\file.txt")
    {
        // do stuff
    }
}

编辑:如果你知道有关该文件的一些细节,你可以用最有效的方式来获取最后一行。例如,也许当您阅读文件时,您可以消除您所读取的内容,因此下次更新时,您只需抓住其中的任何内容并输出即可。也许您知道一次添加一行,然后您的代码可以立即跳转到文件的最后一行。等

答案 1 :(得分:3)

尽管FileSystemWatcher是最简单的解决方案,但我发现它在实际中是不可靠的...通常可以使用新内容更新文件,但FileSystemWatcher直到秒后才会触发事件而且经常永远不会。

我发现解决此问题的唯一可靠方法是使用System.Timers.Timer对象定期检查文件的更改并检查文件大小。

我写了一个小课程,在这里演示了这个:

https://gist.github.com/ant-fx/989dd86a1ace38a9ac58

使用示例

var monitor = new LogFileMonitor("c:\temp\app.log", "\r\n");

monitor.OnLine += (s, e) =>
{
    // WARNING.. this will be a different thread...
    Console.WriteLine(e.Line);
};

monitor.Start();

这里唯一真正的缺点(除了文件大小检查引起的轻微性能延迟)是因为它使用System.Timers.Timer回调来自不同的线程。

如果您使用的是Windows窗体或WPF应用程序,则可以轻松修改该类以接受SynchronizingObject,这将确保从同一个线程调用事件处理程序事件。

答案 2 :(得分:1)

正如@Prescott建议的那样,使用FileSystemWatcher。并确保使用适当的FileShare模式打开文件(FileShare.ReadWrite似乎合适),因为服务器仍可能打开该文件。如果您尝试在另一个进程仍在使用文件时独占打开该文件,则打开操作将失败。

另外,为了获得一点性能,你可以记住你已经读过文件的最后一个位置,只读新的部分。

答案 3 :(得分:0)

尝试添加计时器并将Timer.Tick设置为1秒的间隔。在Timer.Tick上运行该功能。

private void myTimer_Tick(object sender, EventArgs e)
{
    ReadLog();
}

答案 4 :(得分:0)

在另一篇帖子c# continuously read file上使用此答案。

这个非常有效,如果文件大小已经改变,它每秒检查一次。

您可以在另一个线程上运行它(或转换为异步代码),但无论如何您需要将文本编组回主线程以附加到文本框。