How to track a text file and continuously display content in a text field

I am making a program that controls a game server. One of the features that I create is the real-time log log monitor.

There is a log file (plain text file) that is updated by the server as it runs.

How can I constantly check the log file and display its contents in a RichTextBox?

I made this simple function, just try and get the contents of the log. Of course, it will be just text on a line and display it in a text field. It will also block the program as long as the loop is running, so I know this is 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 decide to solve live monitoring as easily as possible?

* EDIT *

I am using Prescots solution. great stuff.

I am currently using sreadreader to put text from a file into a text box. I ran into a problem in that whenever I tried to access any gui control in an event handler, the program simply stopped without errors or warnings.

I found out that this is related to threads. I decided 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 .txt file is being used by the server, so I can’t access it because it is “being used by another process”. I can not control this process. Maybe I'm out of luck.

But the file can be opened in notepad while serevr is running, so somehow it should be possible. Perhaps I can make a temporary copy of the file when it updates and reads the copy. Dunno ...

+6
source share
5 answers

Check out the System.IO.FileSystemWatcher class:

 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 information about the file, you can handle the most efficient way to get the last line. For example, it’s possible that when you read a file, you can destroy what you read, so the next time it is updated, you just take everything that is and output it. You may know that one line is added at a time, then your code can go right to the last line of the file. Etc.

+13
source

Although FileSystemWatcher is the easiest solution, I found it unreliable in practice. Often a file can be updated with new content, but FileSystemWatcher does not fire an event until a few seconds later and often never.

The only reliable way I found for this is to check for changes to the file on a regular basis using the System.Timers.Timer object and check the file size.

I wrote a small class that demonstrates this here:

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

Usage example

 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 flaw here (besides the slight performance delay caused by checking the file size) is that since it uses System.Timers.Timer , the callback comes from another thread.

If you are using a Windows Forms or WPF application, you can easily change the class to accept a SynchronizingObject , which ensures that event handler events are raised from a single thread.

+3
source

As @Prescott suggested, use FileSystemWatcher . And make sure that you open the file with the appropriate FileShare (it seems that FileShare.ReadWrite ), since the file can still be open by the server. If you try to open the file exclusively while it is still being used by another process, the open operation will fail.

Also, to get a little performance, you could remember the last position to which you had already read the file, and only read the new parts.

+1
source

Try adding a timer and set Timer.Tick to an interval of 1 second. On Timer.Tick you run the function.

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

Use this answer in another C # post read the file continuously .

This file is quite efficient, and it checks once a second if the file size has changed.

You can run it in another stream (or convert it to asynchronous code), but in any case, you will need to redirect the text back to the main stream to add it to the text field.

0
source

Source: https://habr.com/ru/post/911024/


All Articles