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

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

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

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

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

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运行时,文件可以在记事本中打开,所以它必须是可能的。 也许我可以在更新和读取副本时对文件进行临时复制。 不知道…

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

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

尽管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 ,这将确保从同一个线程调用事件处理程序事件。

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

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

尝试添加Timer并将Timer.Tick设置为1秒的间隔。 在Timer.Tick运行该function。

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

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

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

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