I want to read the last 400 lines from a txt file - vb6

I know how to do it in VB.Net but not an idea in vb6.
What I what to achieve is to avoid reading the whole file.
Is that possible?

You could open the file using Random access. Work your way backward a byte at a time, counting the number of carriage return line feed character pairs. Store each line in an array, or something similar, and when you've read your 400 lines, stop.

Cometbill has a good answer.
To open file for Random access:
Open filename For Random Access Read As #filenumber Len = reclength
To get the length of the file in Bytes:
FileLen(ByVal PathName As String) As Long
To read from Random access file:
Get [#]filenumber,<[recnumber]>,<varname>
IMPORTANT: the <varname> from the Get function must be a fixed length string Dim varname as String * 1, otherwise it will error out with Bad record length (Error 59) if the variable is declared as a variable length string like this Dim varname as String
EDIT:
Just wanted to point out that in Dim varname as String * 1 you are defining a fixed length string and the length is 1. This is if you wish to use the read-1-byte-backwards approach. If your file has fixed length records, there is no need to go 1 byte at a time, you can read a record at a time (don't forget to add 2 bytes for carriage return and new line feed). In the latter case, you would define Dim varname as String * X where X is the record length + 2. Then a simple loop going backwards 400 times or untill reaching the beginning of the file.

The following is my take on this. This is more efficient than the previous two answers if you have a very large file, since we don't have to store the entire file in memory.
Option Explicit
Private Sub Command_Click()
Dim asLines() As String
asLines() = LoadLastLinesInFile("C:\Program Files (x86)\VMware\VMware Workstation\open_source_licenses.txt", 400)
End Sub
Private Function LoadLastLinesInFile(ByRef the_sFileName As String, ByVal the_nLineCount As Long) As String()
Dim nFileNo As Integer
Dim asLines() As String
Dim asLinesCopy() As String
Dim bBufferWrapped As Boolean
Dim nLineNo As Long
Dim nLastLineNo As Long
Dim nNewLineNo As Long
Dim nErrNumber As Long
Dim sErrSource As String
Dim sErrDescription As String
On Error GoTo ErrorHandler
nFileNo = FreeFile
Open the_sFileName For Input As #nFileNo
On Error GoTo ErrorHandler_FileOpened
' Size our buffer to the number of specified lines.
ReDim asLines(0 To the_nLineCount - 1)
nLineNo = 0
' Read all lines until the end of the file.
Do Until EOF(nFileNo)
Line Input #nFileNo, asLines(nLineNo)
nLineNo = nLineNo + 1
' Check to see whether we have got to the end of the string array.
If nLineNo = the_nLineCount Then
' In which case, flag that we did so, and wrap back to the beginning.
bBufferWrapped = True
nLineNo = 0
End If
Loop
Close nFileNo
On Error GoTo ErrorHandler
' Were there more lines than we had array space?
If bBufferWrapped Then
' Create a new string array, and copy the bottom section of the previous array into it, followed
' by the top of the previous array.
ReDim asLinesCopy(0 To the_nLineCount - 1)
nLastLineNo = nLineNo
nNewLineNo = 0
For nLineNo = nLastLineNo + 1 To the_nLineCount - 1
asLinesCopy(nNewLineNo) = asLines(nLineNo)
nNewLineNo = nNewLineNo + 1
Next nLineNo
For nLineNo = 0 To nLastLineNo
asLinesCopy(nNewLineNo) = asLines(nLineNo)
nNewLineNo = nNewLineNo + 1
Next nLineNo
' Return the new array.
LoadLastLinesInFile = asLinesCopy()
Else
' Simply resize down the array, and return it.
ReDim Preserve asLines(0 To nLineNo)
LoadLastLinesInFile = asLines()
End If
Exit Function
ErrorHandler_FileOpened:
' If an error occurred whilst reading the file, we must ensure that the file is closed
' before reraising the error. We have to backup and restore the error object.
nErrNumber = Err.Number
sErrSource = Err.Source
sErrDescription = Err.Description
Close #nFileNo
Err.Raise nErrNumber, sErrSource, sErrDescription
ErrorHandler:
Err.Raise Err.Number, Err.Source, Err.Description
End Function

Related

Randomly rearrange letters in a word

Using this SO question / answer as a starting point: Splitting a single word into an array of the consituent letters
I have this simple bit of code to take a word and split the word into single letters:
<%
Dim word1, i
word1 = "particle"
For i = 1 To Len(word1)
Response.Write "<p>" & Mid(word1, i, 1) & "</p>"
Next
%>
I would like to know how to take a word (variable length, rather than a word that is 8 characters long as in the example above), and randomly rearrange the letters of the word - so that e.g. particle could be e.g.:
alpreict
lircpaet
ctelaipr
teapclir
raeitclp
This is an example of what I'd like to achieve: https://onlinerandomtools.com/shuffle-letters
However, I realise that is easier said than done.
I wondered if anyone has any advice about how it might be possible to achieve this using Classic ASP please?
Thanks
Here's one way to do it:
Function ShuffleText(p_sText)
Dim iLength
Dim iIndex
Dim iCounter
Dim sLetter
Dim sText
Dim sShuffledText
' Copy text passed as parameter
sText = p_sText
' Get text length
iLength = Len(sText)
For iCounter = iLength To 1 Step -1
' Get random index
iIndex = 1 + Int(Rnd * (iCounter))
' Get character at that index
sLetter = Mid(sText, iIndex, 1)
' Remove character from string
sText = Left(sText, iIndex - 1) & Mid(sText, iIndex + 1)
' Add character to shuffled string
sShuffledText = sShuffledText & sLetter
Next
' Return shuffled text
ShuffleText = sShuffledText
End Function
This code selects a random character in the string, removes it and adds it to a shuffled string. It repeats this process until it has gone through all characters.
There are probably more efficient ways to do this by randomizing an array of numbers first and using those numbers as iIndex, without manipulating the sText string.

unable to search character in a given string using VBScript?

I am trying to find whether the character is present in a given string or not but unable to search and increment value though it is present
Dim testchar,noOfSpecialChar
noOfSpecialChar=0
Dim specialChars
specialChars="*[#.^$|?#*+!)(_=-]."
for lngIndex = 1 to Len("test#123")
testchar = mid("test#123",lngIndex,1)
if((InStr(specialChars,testchar))) then
noOfSpecialChar=noOfSpecialChar+1
end if
next
The problem here is InStr() as highlighted in the documentation;
Returns the position of the first occurrence of one string within another.
We can use this knowledge to create a boolean comparison by checking the return value of InStr() is greater than 0.
Dim testString: testString = "test#123"
Dim testchar, foundChar
Dim noOfSpecialChar: noOfSpecialChar = 0
Dim specialChars: specialChars = "*[#.^$|?#*+!)(_=-]."
For lngIndex = 1 To Len(testString)
testchar = Mid(testString, lngIndex, 1)
'Do we find the character in the search string?
foundChar = (InStr(specialChars, testchar) > 0)
If foundChar Then noOfSpecialChar = noOfSpecialChar + 1
Next

How to read a specific line in txt file vb 6

I would like to read a specific line in a .txt file in a vb 6.0 program. My intrest is where a particular line where a certain text appears. I am trying to apply this code which I got from another project.
Dim strLine As String
Open "E:\Projects\VB\Ubunifu\MyList.txt" For Input As #1
Line Input #1, strLine ' read one line at a time vs entire file
lblCurrent.Caption = strLine
Line Input #1, strLine
lblO.Caption = strLine
Close #1
however this doesnt seem to be working it says "input past end of file"
You can try this:
Private Sub Form_Load()
Text1.MultiLine = True
Open "E:\Projects\VB\Ubunifu\MyList.txt" For Input As #1
Text1.Text = Input$(LOF(1), #1)
lblCurrent.Caption = udf_ReadLine(Text1.Text, 1) ' read line #1
lblCurrent_i.Caption = udf_ReadLine(Text1.Text, 2) ' read line #2
Close #1
End Sub
Private Function udf_ReadLine(ByVal sDataText As String, ByVal nLineNum As Long) As String
Dim sText As String, nI As Long, nJ As Long, sTemp As String
On Error GoTo ErrHandler
sText = ""
nI = 1
nJ = 1
sTemp = ""
While (nI <= Len(sDataText))
Select Case Mid(sDataText, nI, 1)
Case vbCr
If (nJ = nLineNum) Then
sText = sTemp
End If
Case vbLf
nJ = nJ + 1
sTemp = ""
Case Else
sTemp = sTemp & Mid(sDataText, nI, 1)
End Select
nI = nI + 1
Wend
If (nJ = nLineNum) Then
sText = sTemp
End If
udf_ReadLine = sText
Exit Function
ErrHandler:
udf_ReadLine = ""
End Function
I just added a function to read line from a string, and you can keep using the LOF function as you wish, also all of the concept from your original code.
First, if you had searched for your error you would have found the cause, https://msdn.microsoft.com/en-us/library/aa232640(v=vs.60).aspx.
Second, you need to do something to ensure there is anything in the file to read. https://msdn.microsoft.com/en-us/library/aa262732(v=vs.60).aspx
Finally, use a loop to read lines from the file. It appears you want the first line displayed in one label and the second line displayed in another. The code below reads one line at a time from the file, decides if it is reading an odd line number (first line) or even line number (second line) and displays the line in the label. After each line is read it looks for "a certain text" whatever that may be, and if found it exits the loop and closes the file.
Open "E:\Projects\VB\Ubunifu\MyList.txt" For Input As #1
Do While EOF(1) = False
Line Input #1, strLine ' read one line at a time vs entire file
lngLineNum = lngLineNum + 1 'Am I reading an odd or even line number
If lngLineNum Mod 2 <> 0 Then
lblCurrent.Caption = strLine
Else
lblO.Caption = strLine
End If
If InStr(1, strLine, "a cetain text", vbTextCompare) > 0 Then
Exit Do
End If
Loop
Close #1
Note that I did not check that strLine contained anything before calling InStr. If it is empty the InStr function will cause an error. You should add some defensive coding. At the very least an error handler.

Read line-delimited data in VB6

So I have a number of text files that I'm trying to read with Visual Basic. They all have the same formatting:
[number of items in the file]
item 1
item 2
item 3
...etc.
What I'm trying to do is declare an array of the size of the integer in the first line, and then read each line into corresponding parts of the array (so item 1 would be array[0], item 2 would be array[1], etc. However, I'm not sure where to start on this. Any help would be appreciated.
Pretty basic stuff (no pun intended):
Dim F As Integer
Dim Count As Integer
Dim Items() As String
Dim I As Integer
F = FreeFile(0)
Open "data.txt" For Input As #F
Input #F, Count
ReDim Items(Count - 1)
For I = 0 To Count - 1
Line Input #F, Items(I)
Next
Close #F
try this for VB6
Dim file_id As Integer
Dim strline as string
Dim array_item() as string
'Open file
file_id = FreeFile
Open "C:\list.txt" For Input AS #file_id
Dim irow As Integer
irow = 0
'Loop through the file
Do Until EOF(file_id)
'read a line from a file
Line Input #file_id, strline
'Resize the array according to the line read from file
Redim Preserve array_item(irow)
'put the line into the array
array_item(irow) = strline
'move to the next row
irow = irow + 1
Loop
Close #file_id
The VB function you're looking for is "split":
http://www.vb-helper.com/howto_csv_to_array.html
Try this:
Dim FullText As String, l() As String
'''Open file for reading using Scripting Runtime. But you can use your methods
Dim FSO As Object, TS As Object
Set FSO = createbject("Scripting.FileSystemObject")
Set TS = createbject("Scripting.TextStream")
Set TS = FSO.OpenTextFile(FilePath)
TS.ReadLine 'Skip your first line. It isn't needed now.
'''Reading the contents to FullText and splitting to the array.
FullText = TS.ReadAll
l = Split(FullText, vbNewLine) '''the main trick
Splitting automatically resizes l() and stores all data.
Now the l() array has everything you want.

Concat strings returned from RegQueryValueEx

I want to read a string value from the registry and concatenate it with another certain string. I'm calling RegQueryValueEx() , like this:
Dim lResult As Long
Dim sLength As Long
Dim sString As String
sString = Space$(256)
sLength = 256
lResult = RegQueryValueEx(hKey, "MyKey", 0, REG_SZ, ByVal sString, sLength)
MsgBox sString & "blah-blah-blah"
RegQueryValueEx() works fine, I'm getting the needed string in sString and even can display it with MsgBox. But when I try to concat it with "some_string" I get only sString showed. Plz, help me.
Thanks
There is probably a null-character in the string, because VB strings store the length of the string in memory just before the contents of the string. In your case that length is 256. When you load the content using RegQueryValueEx, it null-terminates the string (C-style), but does not change its indicated length, so in the VB world it's still 256 characters long. Then when you append the second string, it gets appended after the first 256 characters, but MsgBox only shows the contents up to the null-character.
Because RegQueryValueEx puts the length of the actual data in sLength, you can add this line before the MsgBox
sString = Left$(sString, sLength)
Precedence issue, maybe? How about trying:
MsgBox(sString & "blah-blah-blah")
Or
Dim sDisplay as String
sDisplay = sString & "blah-blah"
MsgBox sDisplay
Perhaps the string contains a 0-character so that it ends prematurely?
You need to get rid of the null character at the end.
I suggest getting an already written and tested registry module for VB6.
Here is another example from vbnet
But if you just want to get rid of nulls here is one I've used.
Public Function StringFromBuffer(ByRef strBuffer As String) As String
' Extracts String From a Buffer (buffer is terminated with null)
' 06/30/2000 - WSR
Dim lngPos As Long
' attempt to find null character in buffer
lngPos = InStr(1, strBuffer, vbNullChar)
' if found
If lngPos > 0 Then
' return everything before it
StringFromBuffer = Left$(strBuffer, lngPos - 1)
' if not found
Else
' return whole string
StringFromBuffer = strBuffer
End If ' lngPos > 0
End Function ' StringFromBuffer
use Mid$ and sLength to pull the string values out of sString. This way you above strangeness due to extra characters (like the null terminator '0')
Remember when you deal with the Win32 API you have to keep in mind that it assumes C conventions which are not the same as VB Convention. So you have to do some cleanup before sending it along.
It worked for me when I did:
sString = Left$(sString, sLength-1)
the problem indeed was the null character at the end of the string.
Thanks, guys!

Resources