C# 如何监视文本文件并在文本框中连续输出内容
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9757018/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to monitor Textfile and continuously output content in a textbox
提问by Christoffer
I'm making a program that controls a game server. One of the functions I'm making is a live server logfile monitor.
我正在制作一个控制游戏服务器的程序。我正在制作的功能之一是实时服务器日志文件监视器。
There is a logfile (a simple textfile) that gets updated by the server as it runs.
服务器在运行时会更新一个日志文件(一个简单的文本文件)。
How do I continuously check the logfile and output it's content in a RichTextBox?
如何持续检查日志文件并将其内容输出到 RichTextBox 中?
I did this simple function just try and get the content of the log. It will of course just get the text row by row and output it to my textbox. Also it will lock the program for as long as the loop runs, so I know it's useless.
我做了这个简单的功能只是尝试获取日志的内容。它当然只会逐行获取文本并将其输出到我的文本框。只要循环运行,它就会锁定程序,所以我知道它没用。
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();
}
}
}
But how would you go about solving the live monitoring as simple as possible?
但是,您将如何尽可能简单地解决实时监控问题?
* EDIT *
* 编辑 *
I'm using Prescots solution. great stuff.
我正在使用 Prescots 解决方案。好东西。
At the moment I'm using a sstreamreader to put the text from the file to my textbox. I ran into the problem is that, whenever I tried to access any of the gui controls in my event handler the program just stopped with no error or warnings.
目前我正在使用 sstreamreader 将文件中的文本放入我的文本框。我遇到的问题是,每当我尝试访问事件处理程序中的任何 gui 控件时,程序都会停止,没有错误或警告。
I found out that it has to do with threading. I solved that like this:
我发现它与线程有关。我是这样解决的:
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();
}
}
Now my only problem is that the file.txt is used by the server so I can't access it, since it's "being used by another process". I can't control that process.. so maybe I'm out of luck.
现在我唯一的问题是 file.txt 被服务器使用,所以我无法访问它,因为它“被另一个进程使用”。我无法控制这个过程..所以也许我不走运。
But the file can be opened in notepad while the serevr is running, so somehow it must be possible. Perhaps I can do a temp copy of the file when it updates and read the copy. Dunno...
但是该文件可以在 serevr 运行时在记事本中打开,所以一定是可能的。也许我可以在文件更新并读取副本时对其进行临时副本。不知道...
采纳答案by Prescott
Check out the System.IO.FileSystemWatcherclass:
查看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
}
}
Edit: if you know some details about the file, you could handle the most efficent way to get the last line. For example, maybe when you read the file, you can wipe out what you've read, so next time it's updated, you just grab whatever is there and output. Perhaps you know one line is added at a time, then your code can immediately jump to the last line of the file. Etc.
编辑:如果您知道有关该文件的一些详细信息,则可以处理获取最后一行的最有效方法。例如,也许当你阅读文件时,你可以清除你读过的内容,所以下次更新时,你只需抓住那里的任何内容并输出。也许您知道一次添加一行,然后您的代码可以立即跳转到文件的最后一行。等等。
回答by Mr Wednesday
Try adding a Timer and have the Timer.Tickset to an Interval of 1 second. On Timer.Tickyou run the function.
尝试添加一个计时器并将其Timer.Tick设置为 1 秒的间隔。在Timer.Tick您运行该功能时。
private void myTimer_Tick(object sender, EventArgs e)
{
ReadLog();
}
回答by MartinStettner
As @Prescott suggested, use a FileSystemWatcher. And make sure, you open the file with the appropriate FileSharemode (FileShare.ReadWriteseems to be appropriate), since the file might still be opened by the server. If you try to open the file exclusively while it is still used by another process, the open operation will fail.
正如@Prescott 建议的那样,使用FileSystemWatcher. 并确保您使用适当的FileShare模式打开文件(FileShare.ReadWrite似乎是合适的),因为该文件可能仍被服务器打开。如果在另一个进程仍在使用该文件时尝试以独占方式打开该文件,则打开操作将失败。
Also in order to gain a bit of performance, you could remember the last position up to which you already have read the file and only read the new parts.
同样为了获得一些性能,您可以记住您已经读取文件的最后一个位置,并且只读取新部分。
回答by antfx
Although the FileSystemWatcheris the most simple solution I have found it to be unreliable in reality.. often a file can be updated with new contents but the FileSystemWatcherdoes not fire an event until seconds later and often never.
虽然这FileSystemWatcher是最简单的解决方案,但我发现它在现实中是不可靠的......通常可以用新内容更新文件,但FileSystemWatcher直到几秒钟后才触发事件,而且通常永远不会。
The only reliable way I have found to approach this is to check for changes to the file on a regular basis using a System.Timers.Timerobject and checking the file size.
我发现解决此问题的唯一可靠方法是使用System.Timers.Timer对象定期检查文件的更改并检查文件大小。
I have written a small class that demonstrates this available here:
我写了一个小类来演示这里可用的:
https://gist.github.com/ant-fx/989dd86a1ace38a9ac58
https://gist.github.com/ant-fx/989dd86a1ace38a9ac58
Example Usage
示例用法
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();
The only real disadvantage here (apart from a slight performance delay caused by file size checking) is that because it uses a System.Timers.Timerthe callback comes from a different thread.
这里唯一真正的缺点(除了文件大小检查导致的轻微性能延迟)是因为它使用了System.Timers.Timer来自不同线程的回调。
If you are using a Windows Forms or WPF app you could easily modify the class to accept a SynchronizingObjectwhich would ensure the event handler events are called from the same thread.
如果您使用的是 Windows 窗体或 WPF 应用程序,您可以轻松修改该类以接受 a SynchronizingObject,这将确保从同一线程调用事件处理程序事件。
回答by Todd
Use this answer on another post c# continuously read file.
在另一篇文章c# 连续读取文件上使用此答案。
This one is quite efficient, and it checks once per second if the file size has changed.
这个非常有效,它每秒检查一次文件大小是否发生变化。
You can either run it on another thread (or convert to async code), but in any case you would need to marshall the text back to the main thread to append to the textbox.
您可以在另一个线程上运行它(或转换为异步代码),但在任何情况下,您都需要将文本编组回主线程以附加到文本框。

