Search Through Specific Set of Lines and Output Data? - vb.net

I've been struggling with this for a while now, and after extensive searching, I still have yet to find an answer.
In my Visual Basic class, I have a program where I have to get text from a text file (songs.txt), display the genres in a list box, and display corresponding songs in a combo box after a genre is displayed.
Currently, this is my code.
' Variables
Dim strFilePath As String = "E:\Advanced VB\DJPlayList\DJPlayList\songs.txt"
Dim strFileError As String = "File not found. Please try again."
Dim strFileErrorTitle As String = "File Error"
Dim objReader As IO.StreamReader
Dim intCount As Integer = 0
Dim strSongGenre(intCount) As String
Dim i As Integer = 0
' Finding the file
If IO.File.Exists(strFilePath) Then
' Opening the text file
objReader = IO.File.OpenText(strFilePath)
Do Until objReader.Peek = -1
ReDim Preserve strSongGenre(intCount)
strSongGenre(intCount) = objReader.ReadLine
cboMusicGenre.Items.Add(strSongGenre(intCount))
intCount += 1
Loop
Else
MsgBox(strFileError, , strFileErrorTitle)
Close()
End If
This adds all the information from the text file into the array and loads it to the listbox, but I'm stuck at how to output the genre's specifically and the corresponding songs with it.
The text file looks as follows:
All You Need is Love-Beatles 'Song Name
Rock 'Song Genre
4.25 'Song Time
What Hurts the Most-Rascal Flatts
Country
5.25
Touch it-Busta Rhymes
Rap
5.46
My Girl-Temptations
R&B
4.35
What you know?-T.I.
Rap
4.30
How do I specifically get the genre's and the song titles? Thank you for the help in advance

So what is actually happening is that your code is reading every line and storing them all in your ComboBox.
Probably the easiest thing to do at this level would be to create 2 extra temporary string variables and instead of reading 1 line for each iteration of the loop, read the three lines that are related to each other like this
tempName= objReader.ReadLine
strSongGenre(intCount) = objReader.ReadLine
tempDuration = objReader.ReadLine
If you don't want to use the Name and Duration of the song then do nothing with them and they'll be overwritten on the next iteration of the loop
So your final code should look like this
Do Until objReader.Peek = -1
Dim tempName,tempDuration as string
ReDim Preserve strSongGenre(intCount)
tempName= objReader.ReadLine
strSongGenre(intCount) = objReader.ReadLine
tempDuration = objReader.ReadLine
cboMusicGenre.Items.Add(strSongGenre(intCount))
intCount += 1
Loop

Related

VB.Net , Finding data in a text file by ID number

I'm using the VB.net forms application for this project.
so I have a text file like this
7,John,Kimberlake,john#mail.com,27,Bachelor
8,Tiny,Down,tiny#mail.com,34,Master
9,Jeniffer,Kime,Jen#mail.com,22,None
I have 1 textbox and 1 button.
The purpose is that you need to fill an id number to find the data about the person.
Dim Findstring = IO.File.ReadAllText("data.txt")
Dim Data As String = TextBox1.Text
Dim aryTextFile() As String
aryTextFile = Findstring.Split(",")
If aryTextFile.Contains(Data) Then
End If
I tried this and something like finding the index number in the array of the requested id but it didn't work.
Instead of ReadAllText use ReadLines and loop each line to get the data.
Walk through below code and comments.
There are much better ways to do this, But the below is very basic way of doing for easy understanding.
'READ EACH LINE OF THE TEXT FILE.
For Each item As String In IO.File.ReadLines("C:\\Desktop\\test.txt") 'ENSURE VALID PATH HERE
'THIS IS EACH LINE.
Dim Findstring = item
'ASSUME THIS IS TEXT ID FROM TEXT BOX.
Dim ID As String = "8"
'SPLIT THE LINE BASED ON ","
Dim aryTextLine() As String
aryTextLine = Findstring.Split(",")
'NOW YOU HAVE ARRAY TO READ EACH ITEM.
If aryTextLine(0) = ID Then
Dim name = aryTextLine(1)
End If
Next

VB ListBox list ftp directories and remove multiple lines based on number in folder name

I do get a lot of help from this website searching for a solution but at this point I'm completely stuck. I'm not a programmer, still was able to get that far.
The idea of my little project is to download newest version of a program (folder) from FTP server. Unzip files and update current program folder with new files. But before that backup the exiting program folder to a different FTP address.
What I'm struggling with is a way they post program versions (folders) on FTP:
folder structure on FTP
I can't really predict what would be the next folder to download because e.g. for program version:
7.6.16
it might be:
WERSJA_NOWY_TEMPLATE_7.6.17
or
WERSJA_NOWY_TEMPLATE_7.7.01
what ever is being released.
There is an ini file on C drive that holds the current program version. I was able to retrieve that information by reading the line, removing the unnecessary characters and splitting the string:
Dim wersja1 As String = File.ReadAllLines("C:\Windows\file.ini").FirstOrDefault(Function(x) x.Contains("WERSJA="))
Dim characterToRemove1 As String = "WERSJA="
Dim wersja2 As String = Replace(wersja1, characterToRemove1, "")
Dim characterToRemove2 As String = "T"
Dim wersja3 As String = Replace(wersja2, characterToRemove2, "")
Dim wersja4 As String() = wersja3.Split(New Char() {"."c})
Dim w1 As String = wersja4(0)
Dim w2 As String = wersja4(1)
Dim w3 As String = wersja4(2)
e.g. from a line:
WERSJA=7.6.5T
I get:
w1 = 7
w2 = 6
w3 = 5
Then I change the last one (w3) to a two digits number (because of the way folders are named on FTP):
If w3 < 10 Then
w3 = "0" & w3
Else
w3 = w3
End If
So if:
w3 = 5 >> I get 05
w3 = 16 >> I get 16
So far, so good.
In the next step I would like to see a filtered list of program versions (folders) in a ListBox or 2 ListBoxes. I would like to filter the list to see only folder with a bigger number than the current program version, so I can choose the correct one to download.
Why this way? Because if current version is e.g.
7.6.16
and there are 3 new ones e.g.:
7.6.17
7.6.18
7.7.01
I need to download all of them one by one, update program files and start the program to update sql database in order they were released. I can't skip any version on update.
Dim FTPurl As String = "ftp://xx.xx.xxx.xxx/wersje/"
Dim FTPwersja As String = "WERSJA_NOWY_TEMPLATE_*"
Dim FTPlog As String = "xxx"
Dim FTPpass As String = "yyy"
Dim clsRequest As FtpWebRequest = System.Net.WebRequest.Create(FTPurl & FTPwersja)
clsRequest.Credentials = New System.Net.NetworkCredential(FTPlog, FTPpass)
clsRequest.Method = System.Net.WebRequestMethods.Ftp.ListDirectory
Dim listResponse As FtpWebResponse = clsRequest.GetResponse
Dim reader As StreamReader = New StreamReader(listResponse.GetResponseStream())
'folder list
While reader.Peek >= 0
ListBox1.Items.Add(reader.ReadLine)
End While
'remove empty lines
For i As Integer = ListBox1.Items.Count - 1 To 0 Step -1
If ListBox1.GetItemText(ListBox1.Items(i)) = String.Empty Then
ListBox1.Items.RemoveAt(i)
End If
Next i
The above code gives me this result.
I found this code that enables filtering of ListBox but I have no clue on how to convert it to an loop so I would see only folders with bigger numbers than the current version of program:
'filter result in list box
Dim items = From it In ListBox1.Items.Cast(Of Object)()
Where it.ToString().IndexOf("7.5", StringComparison.CurrentCultureIgnoreCase) >= 0
Dim matchingItemList As List(Of Object) = items.ToList()
ListBox1.BeginUpdate()
'ListBox1.Items.Clear() 'add to list
For Each item In matchingItemList
ListBox1.Items.Remove(item) 'remove from list
'ListBox1.Items.Add(item) 'add to list
Next
ListBox1.EndUpdate()
I also have this code to catch choice and prevent crash when clicked on empty line :
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) _
Handles ListBox1.SelectedIndexChanged
Try
Dim LB1choice = ListBox1.SelectedItem.ToString()
Label5.Text = LB1choice
Catch ex As Exception
ListBox1.SelectedIndex = 0
End Try
End Sub
The ideal would be 2 ComboBoxes where 1st would display e.g.
WERSJA_NOWY_TEMPLATE_7.6
WERSJA_NOWY_TEMPLATE_7.7
and based on the choice 2nd ComboBox would list newer subfolders in it e.g.
WERSJA_NOWY_TEMPLATE_7.6.16
WERSJA_NOWY_TEMPLATE_7.6.17
for the 1st one, and:
WERSJA_NOWY_TEMPLATE_7.7.01
for the 2nd one.
I much appreciate if anyone could help me this because it's beyond my skills.

Is it possible to rename the files after copying from source folder?

I copy some test images from source folder.. but i want to make their image name become "001,002" .. and so on.
For Each path As ListViewItem In listbat1.Items
For Each Ftif As String In Directory.GetFiles(path.SubItems(0).Text, "*.tif")
'For n As Integer = 0 To listbat1.Items.Count - 1
Dim Finfo As New FileInfo(Ftif)
My.Computer.FileSystem.CopyFile(Ftif, txtdirectory.Text & imgdir & Finfo.Name & ".tif")
'Next
Next
Next
Is it possible ? if so, can you help me? pls ..
If you want to rename your file using a progressive counter, then you could easily do it using the ToString with a formatting expression. In this example D3 means convert the input number to a string using three numbers and padding with zero if the number is not converted to enough character.
Dim counter as Integer = 0
For Each path As ListViewItem In listbat1.Items
For Each Ftif As String In Directory.GetFiles(path.SubItems(0).Text, "*.tif")
Dim Finfo As New FileInfo(Ftif)
Dim destFile = Path.Combine(txtDirectory.Text, imgdir, counter.ToString("D3") + ".tif")
My.Computer.FileSystem.CopyFile(Ftif, destFile)
Counter = Counter + 1
Next
Next
Notice also that building a path should always be done using the Path class

Start reading massive text file from the end

I would ask if you could give me some alternatives in my problems.
basically I'm reading a .txt log file averaging to 8 million lines. Around 600megs of pure raw txt file.
I'm currently using streamreader to do 2 passes on those 8 million lines doing sorting and filtering important parts in the log file, but to do so, My computer is taking ~50sec to do 1 complete run.
One way that I can optimize this is to make the first pass to start reading at the end because the most important data is located approximately at the final 200k line(s) . Unfortunately, I searched and streamreader can't do this. Any ideas to do this?
Some general restriction
# of lines varies
size of file varies
location of important data varies but approx at the final 200k line
Here's the loop code for the first pass of the log file just to give you an idea
Do Until sr.EndOfStream = True 'Read whole File
Dim streambuff As String = sr.ReadLine 'Array to Store CombatLogNames
Dim CombatLogNames() As String
Dim searcher As String
If streambuff.Contains("CombatLogNames flags:0x1") Then 'Keyword to Filter CombatLogNames Packets in the .txt
Dim check As String = streambuff 'Duplicate of the Line being read
Dim index1 As Char = check.Substring(check.IndexOf("(") + 1) '
Dim index2 As Char = check.Substring(check.IndexOf("(") + 2) 'Used to bypass the first CombatLogNames packet that contain only 1 entry
If (check.IndexOf("(") <> -1 And index1 <> "" And index2 <> " ") Then 'Stricter Filters for CombatLogNames
Dim endCLN As Integer = 0 'Signifies the end of CombatLogNames Packet
Dim x As Integer = 0 'Counter for array
While (endCLN = 0 And streambuff <> "---- CNETMsg_Tick") 'Loops until the end keyword for CombatLogNames is seen
streambuff = sr.ReadLine 'Reads a new line to flush out "CombatLogNames flags:0x1" which is unneeded
If ((streambuff.Contains("---- CNETMsg_Tick") = True) Or (streambuff.Contains("ResponseKeys flags:0x0 ") = True)) Then
endCLN = 1 'Value change to determine end of CombatLogName packet
Else
ReDim Preserve CombatLogNames(x) 'Resizes the array while preserving the values
searcher = streambuff.Trim.Remove(streambuff.IndexOf("(") - 5).Remove(0, _
streambuff.Trim.Remove(streambuff.IndexOf("(")).IndexOf("'")) 'Additional filtering to get only valuable data
CombatLogNames(x) = search(searcher)
x += 1 '+1 to Array counter
End If
End While
Else
'MsgBox("Something went wrong, Flame the coder of this program!!") 'Bug Testing code that is disabled
End If
Else
End If
If (sr.EndOfStream = True) Then
ReDim GlobalArr(CombatLogNames.Length - 1) 'Resizing the Global array to prime it for copying data
Array.Copy(CombatLogNames, GlobalArr, CombatLogNames.Length) 'Just copying the array to make it global
End If
Loop
You CAN set the BaseStream to the desired reading position, you just cant set it to a specfic LINE (because counting lines requires to read the complete file)
Using sw As New StreamWriter("foo.txt", False, System.Text.Encoding.ASCII)
For i = 1 To 100
sw.WriteLine("the quick brown fox jumps ovr the lazy dog")
Next
End Using
Using sr As New StreamReader("foo.txt", System.Text.Encoding.ASCII)
sr.BaseStream.Seek(-100, SeekOrigin.End)
Dim garbage = sr.ReadLine ' can not use, because very likely not a COMPLETE line
While Not sr.EndOfStream
Dim line = sr.ReadLine
Console.WriteLine(line)
End While
End Using
For any later read attempt on the same file, you could simply save the final position (of the basestream) and on the next read to advance to that position before you start reading lines.
What worked for me was skipping first 4M lines (just a simple if counter > 4M surrounding everything inside the loop), and then adding background workers that did the filtering, and if important added the line to an array, while main thread continued reading the lines. This saved about third of the time at the end of a day.

reading file into an array

i have a text file with the following data:
Calculated Concentrations
30.55 73.48 298.25 27.39 40.98 11.21 99.22 33.46 73.99 12.18 30.7
50 28.4 34.33 29.55 70.48 43.09 28.54 50.78 9.68 62.03 63.18 28.4
100 23.83 68.65 10.93 ?????? 31.42 8.16 24.97 8.3 114.97 34.92 15.53
200 32.15 29.98 23.69 ?????? 23.41 33.6 92.03 32.73 13.58 58.44 94.61
400 159.98 18.05 50.94 37.12 15.25 46.75 315.22 69.98 13.58 ?????? 58.77
208.82 11.07 38.15 86.31 35.5 41.88 28.25 5.39 40.83 29.98 54.42 69.48
36.09 13.16 23.26 19.31 147.56 31.86 6.77 19.45 33.6 32.87 205.47 134.21
?????? 17.35 9.96 58.61 13.44 23.97 22.13 145.17 29.55 26.54 37.12 198.33
and i would like to load this data into an array.
how do i enable the user to open a file of his choosing in vb.net?
how do i read these values into an array in vb.net?
i would like to clarify that what person-b has suggested works very very well. specifically the fields = calculationText.split(" ") was exactly what i needed; however, my next issue is the following. the data above is actually in this format:
http://pastebin.com/d29ae565b
where the i need the first value to be 0, then 50, then 100 etc. and i need it to read columns from left to right. the problem is that the values are not reading into the array in this manner. the values are actually reading like this: 6.65, 84.22, ????, 35.15. please help!
To read a file into a String variable, in VB.NET, you can use the System.IO.File.ReadAllText() function. An example is:
Imports System.IO '// placed at the top of the file'
'// some code'
Dim calculationText As String
calculationText = File.ReadAllText("calculations.txt") '// gets all the text in the file'
Where "calculations.txt" is the file name.
To your next point - to allow the user to load a file of their choosing, you can use the OpenFileDialog type. An example:
Dim fileName As String
Dim openDlg As OpenFileDialog
openDlg = New OpenFileDialog() '// make a new dialog'
If openDlg.ShowDialog() = DialogResult.OK Then
'// the user clicked OK'
fileName = openDlg.FileName '// openDlg.FileName is where it keeps the selected name'
End If
Combining this, we get:
Imports System.IO
'// other code in the file'
Dim fileName As String
Dim openDlg As OpenFileDialog
openDlg = New OpenFileDialog() '// make a new dialog'
If openDlg.ShowDialog() = DialogResult.OK Then
'// the user clicked OK'
fileName = openDlg.FileName
End If
Dim calculationText As String
calculationText = File.ReadAllText(fileName)
Now, we need to process the input. First, we need to make a list of decimal numbers. Next, we put everything in the file that is a number in the list:
Dim numbers As List(Of Decimal)
numbers = New List(Of Decimal)() '// make a new list'
Dim fields() As String
fields = calculationText.Split(" ") '// split all the text by a space.'
For Each field As String in fields '// whats inside here gets run for every thing in fields'
Dim thisNumber As Decimal
If Decimal.TryParse(field, thisNumber) Then '// if it is a number'
numbers.Add(thisNumber) '// then put it into the list'
End If
Next
This won't include Calculated Concentrations or ????? in the list. For usable code, just combine the second and last code samples.
EDIT: In response to the comment below.
With List objects, you can index them like this:
Dim myNumber As Decimal
myNumber = numbers(1)
You do not need to use the Item property. Also, when showing it in a message box, you need to turn it into a String type first, like this:
MsgBox(myNumber.ToString())
Once you have the file coming from an OpenFileDialog control or other UI control. Here's something you could do:
Dim filePath As String = "file.txt" ''* file coming from control
Dim fileContents As String = System.IO.File.ReadAllText(filePath)
Dim contentArray() As String = fileContents.Split(" ")
Then you can iterate through the array and TryParse to a number as needed.
OpenFileDialog
Read through character by character, looking for spaces to mark the end of a number, then parse the number an add it to a List. Or if the file is always short, you could use StreamReader.ReadToEnd and String.Split.
Code to start with (auto-converted from C#):
Dim ofd = New OpenFileDialog()
ofd.Title = "Select Data File"
If ofd.ShowDialog() = DialogResult.OK Then
Dim data As New StreamReader(ofd.FileName.ToString())
While data.Read() <> " "c
End While
' Read past Calculated
While data.Read() <> " "c
End While
' Read past Concentrations
Dim concentBuilder As New StringBuilder()
Dim last As Integer
Dim concentrations As New List(Of Double)()
Do
last = data.Read()
If last = " "c OrElse last = -1 Then
Dim concentStr As String = concentBuilder.ToString()
concentBuilder.Remove(0, concentBuilder.Length)
Dim lastConcentration As Double
Dim parseSuccess As Boolean = [Double].TryParse(concentStr, lastConcentration)
If Not parseSuccess Then
Console.[Error].WriteLine("Failed to parse: {0}", concentStr)
Else
concentrations.Add(lastConcentration)
End If
Else
concentBuilder.Append(CChar(last))
End If
Loop While last <> -1
For Each d As Double In concentrations
Console.WriteLine(d)
Next
End If