kiffab

FileReadLine - can you read second last line?

28 posts in this topic

Hi Folks

I have to read a text file in, search for a string and once I find it strip all the stuff I don't need out and leave me with a time. I then have to check the most recent time (last line of file) and the time before that (second last line in file).

How can I read that second last line?

I use StringInStr to locate my keyword then StringLeft to trim. I save this to a temp file (its small - only a handful of lines). I then set a variable for my last line.

$lastLine = FileReadLine($file, -1)

I thought the second last would just be $secondlastLine = FileReadLine($file -2) but no....

Can anyone help?

Thanks.

Share this post


Link to post
Share on other sites



Couldn't you _FileReadToArray($file, $array)

then $line = $array[0]-1

$array[$line] should be the 2nd to last line


010101000110100001101001011100110010000001101001011100110010000

001101101011110010010000001110011011010010110011100100001

My Android cat and mouse game
https://play.google.com/store/apps/details?id=com.KaosVisions.WhiskersNSqueek

We're gonna need another Timmy!

Share this post


Link to post
Share on other sites

I thought the second last would just be $secondlastLine = FileReadLine($file -2) but no....

What's the value of @error of
$secondlastLine = FileReadLine($file, -2)
ConsoleWrite(@error & @CRLF)
(you know there was a comma missing in your statement?)

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Just tried it myself. Returns 1 as @error.

If you can't use the solution koatbliss suggests you could use FileSetPos to position near the end of the file and process the rest of the file:

$hFile = FileOpen("C:temptest.txt")
FileSetPos($hFile, -20, 2) ; Go to the end of the file, then go backward 20 characters
$sResult = FileRead($hFile) ; Read the rest of the file
$aTemp = StringSplit($sResult, @CRLF, 1) ; Split into lines
ConsoleWrite("Second to last line: " & $aTemp[$aTemp[0]-1] & @CRLF) ; Display the second to last line

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

I made this way. A simple Function

I do not know, if it is the most effective way, but work Fine.

;A simple example with txt file.

Local $file = FileOpen("1.txt", 0)

If $file = -1 Then
MsgBox(0, "Error", "Unable to open file.")
Exit
EndIf

msgbox(0,"",LSL($file))

FileClose($file)



Func LSL($filehandle)
local $i=0
While 1
Local $line = FileReadLine($filehandle)
If @error = -1 Then ExitLoop
$i+=1
WEnd
$lastSline=filereadline($filehandle,$i-1)
Return $lastSline
EndFunc

Share this post


Link to post
Share on other sites

Danyfirex,

I do not know, if it is the most effective way

It is very inefficient - because you are reading every line in the file. Take a look at these other ways of doing it:

#include <File.au3>

$sFile = "M:ProgramAutoIt3IncludeWinAPI.au3" ; Adjust to your include path

Local $hFile = FileOpen($sFile, 0)

If $hFile = -1 Then
    MsgBox(0, "Error", "Unable to open file.")
    Exit
EndIf

MsgBox(0, "", LSL($hFile))

FileClose($hFile)

MsgBox(0, "", _Read_Pen_Line())

MsgBox(0, "", _Read_To_Array())

Func LSL($hFilehandle)
    $iBegin = TimerInit()

    Local $i = 0
    While 1
        Local $line = FileReadLine($hFilehandle)
        If @error = -1 Then ExitLoop
        $i += 1
    WEnd
    $lastSline = FileReadLine($hFilehandle, $i - 1)
    ConsoleWrite(TimerDiff($iBegin) & @CRLF)
    Return $lastSline
EndFunc   ;==>LSL

Func _Read_Pen_Line() ; Count the lines and just read the one we want
    $iBegin = TimerInit()
    $iCount = _FileCountLines($sFile)
    $lastSline = FileReadLine($sFile, $iCount - 1)
    ConsoleWrite(TimerDiff($iBegin) & @CRLF)
    Return $lastSline
EndFunc

Func _Read_To_Array() ; Read into an aray and then just extrat the line we want
    $iBegin = TimerInit()
    Local $aLines
    _FileReadToArray($sFile, $aLines)
    ConsoleWrite(TimerDiff($iBegin) & @CRLF)
    Return $aLines[$aLines[0] - 1]
EndFunc

When I run this I find that the first function takes well over twice as long as the last - and nearly twice as long as the second. I would go for the array version each time. ;)

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Danyfirex,

It is very inefficient - because you are reading every line in the file. Take a look at these other ways of doing it:

#include <File.au3>

$sFile = "M:ProgramAutoIt3IncludeWinAPI.au3" ; Adjust to your include path

Local $hFile = FileOpen($sFile, 0)

If $hFile = -1 Then
MsgBox(0, "Error", "Unable to open file.")
Exit
EndIf

MsgBox(0, "", LSL($hFile))

FileClose($hFile)

MsgBox(0, "", _Read_Pen_Line())

MsgBox(0, "", _Read_To_Array())

Func LSL($hFilehandle)
$iBegin = TimerInit()

Local $i = 0
While 1
Local $line = FileReadLine($hFilehandle)
If @error = -1 Then ExitLoop
$i += 1
WEnd
$lastSline = FileReadLine($hFilehandle, $i - 1)
ConsoleWrite(TimerDiff($iBegin) & @CRLF)
Return $lastSline
EndFunc ;==>LSL

Func _Read_Pen_Line() ; Count the lines and just read the one we want
$iBegin = TimerInit()
$iCount = _FileCountLines($sFile)
$lastSline = FileReadLine($sFile, $iCount - 1)
ConsoleWrite(TimerDiff($iBegin) & @CRLF)
Return $lastSline
EndFunc

Func _Read_To_Array() ; Read into an aray and then just extrat the line we want
$iBegin = TimerInit()
Local $aLines
_FileReadToArray($sFile, $aLines)
ConsoleWrite(TimerDiff($iBegin) & @CRLF)
Return $aLines[$aLines[0] - 1]
EndFunc

When I run this I find that the first function takes well over twice as long as the last - and nearly twice as long as the second. I would go for the array version each time. ;)

M23

You are right M23 my function lose more time because read every line. thank you for clearing up that.

Sorry for my english :S

Edited by Danyfirex

Share this post


Link to post
Share on other sites

Danyfirex,

Glad I could help. :)

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Danyfirex

You should definitly read the help file about how FileReadLine works. Putting it simply; if you tell it for example to read lines 3, 4 and 5

It starts at line 1, jumps down 1 line at a time and returns the line you requested (3)

It then jumps back to line 1 and repeats the sequence (1 line at a time) for the next line (4)

The process again repeats for line 5

so in reality it has to go through 12 lines to read line 5 in this example.

In other words; it doesn't start at 1 then jump to 3 followed by a jump to 4 then 5.

That is what makes FileReadLine() so inefficient and makes the array method so much faster.

Edited by GEOSoft

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Hi Guys

Thanks for all the responses. I worked on this yesterday and here's what I did. Files I am reading are < 10 mb in size. Constructive criticism welcome :)

Dim $arrayGC

If Not _FileReadToArray($wrappergc,$arrayGC) Then
   GUICtrlSetData($06_gc_lbl, "No recent full GC")
   GUICtrlSetData($06_gc_dif_lbl, " No recent full GC")
   Return
EndIf

$countForSecondLastGC = UBound($arrayGC)-2

For $x = Ubound($arrayGC) -2 To $countForSecondLastGC  Step -1
   $secondLastGC = $arrayGC[$x]
Next

;Msgbox(0,"",$secondLastGC)

$countForLastGC = UBound($arrayGC)-1

For $x = Ubound($arrayGC) -1 To $countForLastGC  Step -1
   $LastGC = $arrayGC[$x]
Next
GUICtrlSetData($06_gc_lbl, "Last GC: " & $lastGC)
Edited by kiffab

Share this post


Link to post
Share on other sites

Oh and while I am here I have a question regarding the reading of text files :)

My app will read the file every 30 seconds. If the status of something has changed and it's now "down", my app will write an entry to a database table. This appears to work correctly. However, there is one bug. Sometimes the status will change to "up" briefly when it's actually "down". I have identified the cause of this - it's reading the text file when it's incomplete (i.e. still writing). Is there a way to pause it or something if the file is still being written? I don't want to generate false alerts.

Cheers.

Share this post


Link to post
Share on other sites

Why doy ou use a loop?

Dim $arrayGC

If Not _FileReadToArray($wrappergc, $arrayGC) Then
    GUICtrlSetData($06_gc_lbl, "No recent full GC")
    GUICtrlSetData($06_gc_dif_lbl, " No recent full GC")
    Return
EndIf
$secondLastGC = $arrayGC[$arrayGC[0]-1]
$LastGC = $arrayGC[$arrayGC[0]]
GUICtrlSetData($06_gc_lbl, "Last GC: " & $lastGC)


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Which application creates the file? Did you write it yourself or is it a program/script you can't change?


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

@Water - No real reason, I just thoguht I required one. I will look at your alternative. I am using a batch file to create the log file - it's just pulling from event viewer.

@echo off
 
echo wscript.echo ^(Date^(^)-1^)>lastMonth.vbs
for /f %%a in ('cscript //nologo lastMonth.vbs') do set ydate1=%%a
del lastMonth.vbs
set ydate1=%ydate1:/=%
set d=%ydate1:~0,2%
set m=%ydate1:~2,2%
set y=%ydate1:~4,4%
set ydate2=%m%/%d%/%y%,01:01:01AM

cscript C:scriptseventquery.vbs /l system /v /fi "source eq Service Control Manager" /fi "Id eq 7035 or Id eq 7036" /fi "Datetime gt %ydate2%" > Events.txt

Share this post


Link to post
Share on other sites

In this case I would translate your script to AutoIt and pack everything into a single AutoIt script.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

kiffab,

You might adapt the following to quickly read lines from the end of a text file.

;
;
;


#include <constants.au3>
#include <array.au3>

$hFile = FileOpen("your.file.name")
if $hfile = -1 then msgbox(0,"Error on open","")

local $pos = filesetpos($hfile,-4096,$file_end)

$string = FileRead($hFile)

FileClose($hFile)

$a10 = stringsplit($string,@crlf,3)

_arraydisplay($a10)

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

Hi kylomas,

that's exactly the solution I've already posted in post ;)


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

@water, I AM an idiot, sorry...

@kiffab - follow water's advice...

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

I think you have to do more to prove you are an idiot :whistle: ... it was just an oversight.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

#include <FileConstants.au3>
$Pos = 1000

$hFile = FileOpen(@ScriptDir &amp; 'file.au3')

FileSetPos($hFile, -196, $file_end)
$sText = FileRead($hFile)
FileClose($hFile)

For $i = 1 To 5
    $string = _ReadString($Pos, $i)
    MsgBox(0, -$i, $string)
    ClipPut($string)
Next

Func _ReadString(ByRef $Pos, $i)
    $TmpPos = StringInStr($sText, @CRLF, 0, -$i)
    $string = StringMid($sText, $TmpPos + 2, $Pos - $TmpPos - 2)
    $Pos = $TmpPos
    Return $string
EndFunc

Edited by AZJIO

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now