如何监听Textfile并在文本框中持续输出内容?

问题描述 投票:0回答:5

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

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

如何持续检查日志文件并将其内容输出到 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 解决方案。很棒的东西。

目前我正在使用流阅读器将文件中的文本放入我的文本框。 我遇到的问题是,每当我尝试访问事件处理程序中的任何 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 被服务器使用,所以我无法访问它,因为它“正在被另一个进程使用”。我无法控制这个过程,所以也许我运气不好。

但是该文件可以在服务器运行时在记事本中打开,所以无论如何它一定是可能的。也许我可以在文件更新时制作文件的临时副本并读取副本。我不知道。

c#
5个回答
19
投票

查看 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
    }
}

编辑:如果您知道有关文件的一些详细信息,您可以处理获取最后一行的最有效方法。例如,也许当您读取文件时,您可以擦除已读取的内容,因此下次更新时,您只需获取其中的所有内容并输出即可。也许您知道一次添加一行,那么您的代码可以立即跳转到文件的最后一行。等等


7
投票

虽然

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

我发现解决此问题的唯一可靠方法是使用

System.Timers.Timer
对象定期检查文件更改并检查文件大小。

我写了一个小课程来演示这一点,可以在这里找到:

https://gist.github.com/mikedavies-dev/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
,这将确保从同一线程调用事件处理程序事件。


1
投票

正如@Prescott建议的那样,使用

FileSystemWatcher
。并确保使用适当的 FileShare 模式打开文件(
FileShare.ReadWrite
似乎是合适的),因为该文件可能仍由服务器打开。如果您尝试以独占方式打开该文件,而该文件仍被其他进程使用,则打开操作将失败。

此外,为了获得一点性能,您可以记住已读取文件的最后位置,并且只读取新部分。


1
投票

在另一篇文章中使用这个答案c#连续读取文件

这个非常高效,它每秒检查一次文件大小是否已更改。

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


0
投票

尝试添加一个计时器并将

Timer.Tick
设置为 1 秒的间隔。在
Timer.Tick
上运行该函数。

private void myTimer_Tick(object sender, EventArgs e)
{
    ReadLog();
}
© www.soinside.com 2019 - 2024. All rights reserved.