My question is how would I go about monitoring the last line of a log file and displaying it in a txtfield? Here is the scenario:
I have an application running that sends some events to a log file it keeps. Keep in mind that this file is opened by the application. I would like to read the last line of the log file and print that in my app, and then when ever it is updated print the new update.
Additionally a more advanced way would be the last 5 lines of the log file to get a semi-history. An even more advanced way would be to have a scrolling function to track all of it if the user needed to see if they'd missed something.
That partially works, but how would I get it to update as the log updated. I'd rather not keep passing the entire file every time. The log gets rather large, it's for one of our security devices.
So my question is partially answered but now I need to know how to keep updating the entries as the log is updated.
Imports System.IO
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents btnTail As System.Windows.Forms.Button
Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
Friend WithEvents Label1 As System.Windows.Forms.Label
Friend WithEvents TextBox2 As System.Windows.Forms.TextBox
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.btnTail = New System.Windows.Forms.Button()
Me.TextBox1 = New System.Windows.Forms.TextBox()
Me.Label1 = New System.Windows.Forms.Label()
Me.TextBox2 = New System.Windows.Forms.TextBox()
Me.SuspendLayout()
'
'btnTail
'
Me.btnTail.Location = New System.Drawing.Point(272, 464)
Me.btnTail.Name = "btnTail"
Me.btnTail.TabIndex = 0
Me.btnTail.Text = "Tail"
'
'TextBox1
'
Me.TextBox1.Location = New System.Drawing.Point(64, 24)
Me.TextBox1.Name = "TextBox1"
Me.TextBox1.Size = New System.Drawing.Size(552, 20)
Me.TextBox1.TabIndex = 1
Me.TextBox1.Text = ""
'
'Label1
'
Me.Label1.Location = New System.Drawing.Point(0, 24)
Me.Label1.Name = "Label1"
Me.Label1.Size = New System.Drawing.Size(64, 32)
Me.Label1.TabIndex = 2
Me.Label1.Text = "Filename and path:"
'
'TextBox2
'
Me.TextBox2.Location = New System.Drawing.Point(8, 72)
Me.TextBox2.Multiline = True
Me.TextBox2.Name = "TextBox2"
Me.TextBox2.ReadOnly = True
Me.TextBox2.ScrollBars = System.Windows.Forms.ScrollBars.Vertical
Me.TextBox2.Size = New System.Drawing.Size(608, 376)
Me.TextBox2.TabIndex = 3
Me.TextBox2.Text = ""
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(624, 501)
Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.TextBox2, Me.Label1, Me.TextBox1, Me.btnTail})
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
#End Region
Private Sub btnTail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTail.Click
Dim SRead As Stream
Try
SRead = File.OpenRead(TextBox1.Text)
Dim SrRead As StreamReader = New StreamReader(SRead, System.Text.Encoding.ASCII)
' set the file pointer to the beginning
SrRead.BaseStream.Seek(0, SeekOrigin.Begin)
SrRead.BaseStream.Position = SrRead.BaseStream.Length - 500
Dim buffer(500) As Char
SrRead.Read(buffer, 0, (SrRead.BaseStream.Length - SrRead.BaseStream.Position))
TextBox2.Text = buffer
SrRead.DiscardBufferedData()
SrRead.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class
although you may want to add some code to trap for files less than 500 bytes, or of course you may want to read more than 500 bytes from the end. Hope this helps.
I forgot to scroll the textbox to the bottom, so here is that part:
VB Code:
'scroll to the bottom
txtLog.SelectionStart = txtLog.Text.Length
txtLog.ScrollToCaret()
And if you want to just grab a certain number of 'lines' from the log then you can use this. I used a Queue to just grab the bottom lines other than that it is a lot like Slow_Leaners that grabs the end in bytes.
VB Code:
Private Sub UpdateText(ByVal sender As System.Object, ByVal e As FileSystemEventArgs)
Try
Dim SRead As Stream
'open file
SRead = File.OpenRead("Log.txt")
Dim SrRead As StreamReader = New StreamReader(SRead, System.Text.Encoding.ASCII)
'setup queue
Dim q As New Queue()
'read lines into que and only keep the last lines upto the value of txtLinesToTail
While (SrRead.Peek() > -1)
Dim Buffer As String = SrRead.ReadLine()
'add line to queue
q.Enqueue(Buffer)
'ditch any lines more than needed
If q.Count > CInt(txtLinesToTail.Text) Then q.Dequeue()
While (SrRead.Peek() > -1)
Dim Buffer As String = SrRead.ReadLine()
'add line to queue
q.Enqueue(Buffer)
'ditch any lines more than needed
If q.Count > CInt(txtLinesToTail.Text) Then q.Dequeue()
End While
Doesn't that actually read the entire file? What if the file's 10mb or more?
That is true but there is no way to tell how long a line is (that I know of). So you have to read it all in and then only keep the last x amount of lines. Although I thought yours was an excellent example of doing it conversatively with bytes.
So if you wanted to be extra careful, before you move the .BaseStream.Position to a certain position you'd check to see how long the file was (I believe FileInfo.Length returns bytes) and then trap against that to keep an exception from happening. Right?
...
duh woops how long a LINE is eh? As in how many lines in a given file? Yeah I see what you mean. :/
Yeah I've been working with reading delimited text files rather a lot lately so I figured ReadLine was right out for this problem, for just the reason you say.