Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Reverse entries in a text file

Status
Not open for further replies.

SkennyR

Programmer
Mar 7, 2004
157
US
Hi all..
I have a program I wrote that outputs abnormal program activity to a text file.
Example: Say user tries to choose a non-existant path:
message= "Path error encountered."
Goes to a sub called logme:
sub logme
open "errorlog.txt" for append as #1
print #1, message
close 1

Pretty simple I know.
But what if I wanted to limit the errorlog.txt file size to 100 entries?
Is there a simple way to delete entry #1 when entry #101 is made?

Currently program counts the number of lines in the file before writing to it. If over 100 then it copies everything except entry #1 to another file (erorlog.tmp). It then adds entry 101 to errorlog.tmp.
It then deletes errorlog.txt, renames errorlog.tmp to errorlog.txt. This results in 100 entries, first in-first out.
There has got to be a cleaner way to do this, and I know you are the guys to ask.
Thanks.
 
no better way with sequential files.

But creating a temp file is really not required (although benefic for a safeguard point of view).
You can load the whole file into a array, add your new entry, and then open the original file as output, and write your 2-101 entries to it again.



Regards

Frederico Fonseca
SysSoft Integrated Ltd
 
Thanks,,
That is an idea.
But wont that take a huge chunk of memory?
And after I read my post, i think I need to clarify the title.
SEQ files write first on top, last on the bottom of the file.
I was wondering if there is anyway to reverse this order.
I think it would be easier to remove the bottom line of the file than it would be to remove the top line.
 
There will be some sort of cost no matter what you do. 100 records in memory is nothing really if they aren't extremely long. It does have a clumsy feel to it though.

One alternative might be a fixed-length record random file. Let the first record contain a "last entry" record index field and the next 100 records hold log entries. You just write to LastUsed + 1, wrapping back to the beginning in a circular fashion when you get past the last slot.

Yes you'll need to have a "log viewer" program, or at least something that can unroll the log file into a sequential "log report" textile.


Of course at that point you may as well have a "viewer/reporter" that does the trimming back to 100 entries on viewing.

But there isn't anything that will impose some alternative structure on a stream file for "free." It's a case of "pay me now or pay me later.
 
Thanks for the input.
Could you give me a sample of using the random file?
 
Take a look at the below thread:

thread222-689374

Swi
 
There is a bit of work to it, but you only need to write the code once. Here's a combined logger/viewer:
Code:
Option Explicit
'
'Logs events up to LOG_MAX entries and then recycles
'log records.
'
'Form has 4 controls:
'
'   1 multiline textbox txtLog
'   3 command buttons cmdLogA, cmdLogB, & cmdViewLog
'
'cmdViewLog displays log entries "newest to oldest"
'

Private Const LOG_FILE As String = "appevents.log"
Private Const LOG_MAX As Long = 10

Private Type LogControl
    LastEntry As Long
End Type

Private Type LogEntry
    Timestamp As String * 24
    EventClass As String * 1 'vbNullChar for unused records
    Description As String * 100
End Type

Private Function FilePresent(ByVal FileName As String) As Boolean
    On Error Resume Next
    FileLen FileName
    FilePresent = Err.Number = 0
End Function

Private Sub LogEvent(ByVal EventClass As String, _
                     ByVal Description As String)
    Dim blnNoFile As Boolean
    Dim intFile As Integer
    Dim leRecord As LogEntry
    Dim lcRecord As LogControl
    
    With leRecord
        .Timestamp = Format$(Now(), "yyyy/mm/dd \@ hh:nn:ss AM/PM")
        .EventClass = EventClass
        .Description = Description
    End With
    
    blnNoFile = Not FilePresent(LOG_FILE)
    intFile = FreeFile(0)
    Open LOG_FILE For Random As #intFile Len = Len(leRecord)
    If blnNoFile Then
        lcRecord.LastEntry = 1
    Else
        Get #intFile, LOG_MAX + 1, lcRecord
        lcRecord.LastEntry = (lcRecord.LastEntry Mod LOG_MAX) + 1
    End If
    Put #intFile, LOG_MAX + 1, lcRecord
    Put #intFile, lcRecord.LastEntry, leRecord
    Close #intFile
End Sub

Private Sub cmdLogA_Click()
    LogEvent "A", "Testing, testing"
End Sub

Private Sub cmdLogB_Click()
    LogEvent "B", "The quick brown fox jumped over the lazy dog"
End Sub

Private Sub cmdViewLog_Click()
    Dim intFile As Integer
    Dim lcRecord As LogControl
    Dim lngRec As Long
    Dim leRecord As LogEntry
    
    If FilePresent(LOG_FILE) Then
        intFile = FreeFile(0)
        Open LOG_FILE For Random As #intFile Len = Len(leRecord)
        Get #intFile, LOG_MAX + 1, lcRecord
        lngRec = lcRecord.LastEntry
        txtlog.Text = ""
        Do
            Get #intFile, lngRec, leRecord
            With leRecord
                If .EventClass <> vbNullChar Then
                    txtlog.Text = txtlog.Text _
                                & .Timestamp & " " _
                                & .EventClass & " " _
                                & RTrim$(.Description) & vbNewLine
                End If
            End With
            lngRec = ((lngRec + LOG_MAX - 2) Mod LOG_MAX) + 1
        Loop While lngRec <> lcRecord.LastEntry _
               And leRecord.EventClass <> vbNullChar
        Close #intFile
    Else
        txtlog.Text = "*no entries*"
    End If
End Sub
This example puts the "control" record after the log entry records (set to just 10 here).
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top