C# 如何监控文本文件并在文本框中连续输出内容?

C# 如何监控文本文件并在文本框中连续输出内容?,c#,C#,我正在制作一个控制游戏服务器的程序。我正在做的功能之一是一个实时服务器日志文件监视器 有一个日志文件(一个简单的文本文件),在运行时由服务器更新 如何连续检查日志文件并将其内容输出到RichTextBox中 我做了这个简单的函数,只是尝试获取日志的内容。当然,它只需逐行获取文本并将其输出到我的文本框中。而且只要循环运行,它就会锁定程序,所以我知道这是无用的 public void ReadLog() { using (StreamReader reader = new StreamReade

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

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

如何连续检查日志文件并将其内容输出到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,所以我无法访问它,因为它“正在被另一个进程使用”。我无法控制这个过程,所以也许我运气不好


但是,当服务器运行时,文件可以在记事本中打开,所以无论如何,这是可能的。也许我可以在文件更新并读取副本时对其进行临时复制。我不知道。

尝试添加一个计时器,并将
计时器设置为间隔1秒。在
定时器上。勾选
运行该函数

private void myTimer_Tick(object sender, EventArgs e)
{
    ReadLog();
}
查看课程:


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

按照@Prescott的建议,使用
文件系统观察程序。并确保以适当的模式打开文件(
FileShare.ReadWrite
似乎合适),因为文件可能仍由服务器打开。如果在另一个进程仍在使用该文件时尝试以独占方式打开该文件,则打开操作将失败


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

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

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

我在这里编写了一个小类来演示这一点:

示例用法

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应用程序,您可以轻松修改该类以接受同步对象,这将确保从同一线程调用事件处理程序事件。

在另一篇文章中使用此答案

这是一个非常有效的方法,它每秒检查一次文件大小是否已更改


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

使用计时器。。。每10秒或5秒检查一次…谢谢!那会有很大帮助。我对这个很陌生。。。现在我遇到了获取“方法必须有一个返回类型”的noob问题,如果我将Watch()类设置为“public void Watch()”,则不会发生这种情况。我可能是在错误的地方或方式创建它。我把它放在我的“公共部分类MYPROGRAM:Form”中啊,是的,对不起,我写周围的代码非常快。您可以删除watcher代码,并在适当的时候将其放入您的代码中,而不必像我上面提到的那样放入Watch()函数中。谢谢!我刚刚在第一个问题中添加了一些信息(这里是新的..这样做是否违反了任何规则?)如果您的问题得到了回答,您可能希望将其标记为已回答并开始一个新问题。如果我使用StreamReader,它会变得更干净吗?我想为了寻找一个特定的位置,你必须直接访问底层的
FileStream
(通过
position
属性)。因此,首先创建
文件流
,转到正确的位置,在流的顶部构造一个
流读取器
,读取数据,然后再次从
文件流
获取最终位置。(我没有试过,我希望它能像描述的那样工作…)
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();