Reading a file in and outputting to two listboxes - vb.net

I'm using Imports System.IO and StreamReader inside a Windows Forms App.
I am trying to take a file, read it in, and output it into two listboxes. The text file is formatted like this.
Blue, 23.7
Green, 60.1
Black, 45.3
I want to output colours that have a higher value than 50 into one listbox, and the ones lower into another. So far all I've done is output the whole list into a textbox. The code for that looks like this:
srTextFile = File.OpenText(dataFile)
Do While srTextFile.EndOfStream = False
'read file by line, use the comma as a splitter
thisFile = srTextFile.ReadLine().Split(",")
For i As Integer = 0 To thisFile.GetUpperBound(0)
txtFileDisplay.AppendText(thisFile(i) &vbTab)
Next
txtFileDisplay.AppendText(vbCrLf)
Loop
I'm completely new to reading in files. I really don't know what I'm doing. I'm pretty new to arrays as well.
Thanks!

By using a class, you can create objects containing the color names as well as the double value and add those to the listboxes.
Public Class ColorValue
Public Property Name As String
Public Property Value As Double
Public Overrides Function ToString() As String
Return $"{Name} ({Value})"
End Function
End Class
Note that I've overridden ToString, because ListBox uses it to display a text for each item.
Now, you can add colors to the listboxes like this
For Each line As String In File.ReadLines(dataFile)
Dim parts As String() = line.Split(","c)
If parts.Length = 2 Then 'If line is well-shaped.
Dim value As Double
Double.TryParse(Trim(parts(1)), value) 'Gets 0 into value if conversion fails.
Dim color = New ColorValue With {.Name = parts(0), .Value = value}
If value > 50.0 Then
listBox1.Items.Add(color)
Else
listBox2.Items.Add(color)
End If
End If
Next
Now, you can get a color value back with
Dim c As ColorValue = DirectCast(listBox1.SelectedItem, ColorValue)
Dim n As String = c.Name
Dim v As Double = c.Value

You can make use of the System.IO.File Class to do this
Simply read the text file into a string
Split the string into lines
Split the lines into arrays
Parse the strings into doubles
Compare the doubles and get values greater than 50 into a seperate listbox
You can write your code like this:
For Each line As String In File.ReadAllLines("Your file here")
Dim Spl() AS String = Split(line, ",")
'Convert string value to integer
Dim myNum As Double = Double.Parse(Spl(1))'The number is the second item in the array
If myNum < 50.0 Then
'Add to your first Listbox here using
'Listbox.Add(myNum)
Else
'Add to your second Listbox here using
'Listbox.Add(myNum)
End If
Next

Related

Get a specific value from the line in brackets (Visual Studio 2019)

I would like to ask for your help regarding my problem. I want to create a module for my program where it would read .txt file, find a specific value and insert it to the text box.
As an example I have a text file called system.txt which contains single line text. The text is something like this:
[Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]
What i want to do is to get only the last name value "xxx_xxx" which every time can be different and insert it to my form's text box
Im totally new in programming, was looking for the other examples but couldnt find anything what would fit exactly to my situation.
Here is what i could write so far but i dont have any idea if there is any logic in my code:
Dim field As New List(Of String)
Private Sub readcrnFile()
For Each line In File.ReadAllLines(C:\test\test_1\db\update\network\system.txt)
For i = 1 To 3
If line.Contains("Last Name=" & i) Then
field.Add(line.Substring(line.IndexOf("=") + 2))
End If
Next
Next
End Sub
Im
You can get this down to a function with a single line of code:
Private Function readcrnFile(fileName As String) As IEnumerable(Of String)
Return File.ReadLines(fileName).Where(Function(line) RegEx.IsMatch(line, "[[[]Last Name=(?<LastName>[^]]+)]").Select(Function(line) RegEx.Match(line, exp).Groups("LastName").Value)
End Function
But for readability/maintainability and to avoid repeating the expression evaluation on each line I'd spread it out a bit:
Private Function readcrnFile(fileName As String) As IEnumerable(Of String)
Dim exp As New RegEx("[[[]Last Name=(?<LastName>[^]]+)]")
Return File.ReadLines(fileName).
Select(Function(line) exp.Match(line)).
Where(Function(m) m.Success).
Select(Function(m) m.Groups("LastName").Value)
End Function
See a simple example of the expression here:
https://dotnetfiddle.net/gJf3su
Dim strval As String = " [Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]"
Dim strline() As String = strval.Split(New String() {"[", "]"}, StringSplitOptions.RemoveEmptyEntries) _
.Where(Function(s) Not String.IsNullOrWhiteSpace(s)) _
.ToArray()
Dim lastnameArray() = strline(1).Split("=")
Dim lastname = lastnameArray(1).ToString()
Using your sample data...
I read the file and trim off the first and last bracket symbol. The small c following the the 2 strings tell the compiler that this is a Char. The braces enclosed an array of Char which is what the Trim method expects.
Next we split the file text into an array of strings with the .Split method. We need to use the overload that accepts a String. Although the docs show Split(String, StringSplitOptions), I could only get it to work with a string array with a single element. Split(String(), StringSplitOptions)
Then I looped through the string array called splits, checking for and element that starts with "Last Name=". As soon as we find it we return a substring that starts at position 10 (starts at zero).
If no match is found, an empty string is returned.
Private Function readcrnFile() As String
Dim LineInput = File.ReadAllText("system.txt").Trim({"["c, "]"c})
Dim splits = LineInput.Split({"]["}, StringSplitOptions.None)
For Each s In splits
If s.StartsWith("Last Name=") Then
Return s.Substring(10)
End If
Next
Return ""
End Function
Usage...
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = readcrnFile()
End Sub
You can easily split that line in an array of strings using as separators the [ and ] brackets and removing any empty string from the result.
Dim input As String = "[Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]"
Dim parts = input.Split(New Char() {"["c, "]"c}, StringSplitOptions.RemoveEmptyEntries)
At this point you have an array of strings and you can loop over it to find the entry that starts with the last name key, when you find it you can split at the = character and get the second element of the array
For Each p As String In parts
If p.StartsWith("Last Name") Then
Dim data = p.Split("="c)
field.Add(data(1))
Exit For
End If
Next
Of course, if you are sure that the second entry in each line is the Last Name entry then you can remove the loop and go directly for the entry
Dim data = parts(1).Split("="c)
A more sophisticated way to remove the for each loop with a single line is using some of the IEnumerable extensions available in the Linq namespace.
So, for example, the loop above could be replaced with
field.Add((parts.FirstOrDefault(Function(x) x.StartsWith("Last Name"))).Split("="c)(1))
As you can see, it is a lot more obscure and probably not a good way to do it anyway because there is no check on the eventuality that if the Last Name key is missing in the input string
You should first know the difference between ReadAllLines() and ReadLines().
Then, here's an example using only two simple string manipulation functions, String.IndexOf() and String.Substring():
Sub Main(args As String())
Dim entryMarker As String = "[Last Name="
Dim closingMarker As String = "]"
Dim FileName As String = "C:\test\test_1\db\update\network\system.txt"
Dim value As String = readcrnFile(entryMarker, closingMarker, FileName)
If Not IsNothing(value) Then
Console.WriteLine("value = " & value)
Else
Console.WriteLine("Entry not found")
End If
Console.Write("Press Enter to Quit...")
Console.ReadKey()
End Sub
Private Function readcrnFile(ByVal entry As String, ByVal closingMarker As String, ByVal fileName As String) As String
Dim entryIndex As Integer
Dim closingIndex As Integer
For Each line In File.ReadLines(fileName)
entryIndex = line.IndexOf(entry) ' see if the marker is in our line
If entryIndex <> -1 Then
closingIndex = line.IndexOf(closingMarker, entryIndex + entry.Length) ' find first "]" AFTER our entry marker
If closingIndex <> -1 Then
' calculate the starting position and length of the value after the entry marker
Dim startAt As Integer = entryIndex + entry.Length
Dim length As Integer = closingIndex - startAt
Return line.Substring(startAt, length)
End If
End If
Next
Return Nothing
End Function

Is it possible to use String.Split() when NewLine is the delimiter?

I have a question which asks me to calculate something from an input file. The problem is, the lines in the file don't use any special character as delimiter, like , or |. I will show it down below.
Data Communication
20
Visual Basic
40
The output I need to write to another file should look like this:
Data communication 20
Visual Basic 40
Total Books : 60
The problem is, how can I specify the delimiter? Like when there is a symbol as in strArray = strLine.Split(","). Since there is nothing I can use as delimiter, how can I split the file content?
There's no real need to split the text in the input file, when you can read a file line by line using standard methods.
You can use, e.g., a StreamReader to read the lines from the source file, check whether the current line is just text or it can be converted to a number, using Integer.TryParse and excluding empty lines.
Here, when the line read is not numeric, it's added as a Key in a Dictionary(Of String, Integer), unless it already exists (to handle duplicate categories in the source file).
If the line represents a number, it's added to the Value corresponding to the category Key previously read, stored in a variable named previousLine.
This setup can handle initial empty lines, empty lines in the text body and duplicate categories, e.g.,
Data Communication
20
Visual Basic
40
C#
100
Visual Basic
10
Other stuff
2
C++
10000
Other stuff
1
If a number is instead found in the first line, it's treated as a category.
Add any other check to handle a different structure of the input file.
Imports System.IO
Imports System.Linq
Dim basePath = "[Path where the input file is stored]"
Dim booksDict = New Dictionary(Of String, Integer)
Dim currentValue As Integer = 0
Dim previousLine As String = String.Empty
Using sr As New StreamReader(Path.Combine(basePath, "Books.txt"))
While sr.Peek > -1
Dim line = sr.ReadLine().Trim()
If Not String.IsNullOrEmpty(line) Then
If Integer.TryParse(line, currentValue) AndAlso (Not String.IsNullOrEmpty(previousLine)) Then
booksDict(previousLine) += currentValue
Else
If Not booksDict.ContainsKey(line) Then
booksDict.Add(line, 0)
End If
End If
End If
previousLine = line
End While
End Using
Now, you have a Dictionary where the Keys represent categories and the related Value is the sum of all books in that category.
You can Select() each KeyValuePair of the Dictionary and transform it into a string that represents the Key and its Value (Category:Number).
Here, also OrderBy() is used, to order the categories alphabetically, in ascending order; it may be useful.
File.WriteAllLines is then called to store the strings generated.
In the end, a new string is appended to the file, using File.AppendAllText, to write the sum of all books in all categories. The Sum() method sums all the Values in the Dictionary.
Dim newFilePath = Path.Combine(basePath, "BooksNew.txt")
File.WriteAllLines(newFilePath, booksDict.
Select(Function(kvp) $"{kvp.Key}:{kvp.Value}").OrderBy(Function(s) s))
File.AppendAllText(newFilePath, vbCrLf & "Total Books: " & booksDict.Sum(Function(kvp) kvp.Value).ToString())
The output is:
C#:100
C++:10000
Data Communication:20
Other stuff:3
Visual Basic:50
Total Books: 10173
Sure.. System.IO.File.ReadAllLines() will read the whole file and split into an array based on newlines, so you'll get an array of 4 elements. You can process it with a flipflop boolean to get alternate lines, or you can try and parse the line to a number and if it works, then its a number and if not, it's a string. If it's a number take the string you remembered (using a variable) from the previous loop
Dim arr = File.ReadALlLines(...)
Dim isStr = True
Dim prevString = ""
For Each s as String in arr
If isStr Then
prevString = s
Else
Console.WriteLine($"The string is {prevString} and the number is {s}")
End If
'flip the boolean
isStr = Not isStr
Next s
I used File.ReadAllLines to get an array containing each line in the file. Since the size of the file could be larger than the sample shown, I am using a StringBuilder. This save having to throw away and create a new string on each iteration of the loop.
I am using interpolated strings indicated by the $ preceding the quotes. This allows you to insert variables into the string surrounded by braces.
Note the Step 2 in the For loop. i will increment by 2 instead of the default 1.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lines = File.ReadAllLines("input.txt")
Dim sb As New StringBuilder
Dim total As Integer
For i = 0 To lines.Length - 2 Step 2
sb.AppendLine($"{lines(i)} {lines(i + 1)}")
total += CInt(lines(i + 1))
Next
sb.AppendLine($"Total Books: {total}")
TextBox1.Text = sb.ToString
End Sub

I am trying to figure out how to read a text file into an array in vb.net

I'm trying to create a program in vb.net (forms) to process data from a UVvis spectrometer.
The txt file output looks as following.
"180809_QuartzRefTrans.spc - RawData"
"Wavelength nm.","T%"
400.00,90.822
401.00,90.800
402.00,90.823
403.00,90.811
404.00,90.803
405.00,90.804
406.00,90.816
407.00,90.811
408.00,90.833
409.00,90.837
410.00,90.847
411.00,90.827
412.00,90.839
413.00,90.851
414.00,90.828
415.00,90.879
416.00,90.846
and so on.
What I am trying to do is read the data it into an array so I can manipulate the columns. I need to be able to skip the first two lines so that all I have is numerical data. I also need it to sort the array from lowest to highest (wavelengths). Sometimes we run from 800->200 nm then accidentally put in 200->800 nm
Imports System.IO
Imports System.Windows.Forms.DataVisualization.Charting
Public Class Form1
Public Class RefTrans
Public Property Wavelength As Double
Public Property Transpercent As Double
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim strtext As String
OpenFileDialog1.Title = "Open Text Files"
OpenFileDialog1.ShowDialog()
strtext = OpenFileDialog1.FileName
TextBox1.Text = My.Computer.FileSystem.GetName(strtext)
Label1.Text = My.Computer.FileSystem.GetName(strtext)
Dim line1 As String
Dim output1 As New ArrayList
Using sr As New IO.StreamReader(strtext)
sr.ReadLine()
sr.ReadLine()
Do While sr.Peek() >= 0
line1 = sr.ReadLine()
output1.Add(line1)
Loop
End Using
If strtext <> "" Then
Dim SR As New StreamReader(strtext)
SR.ReadLine()
Do Until SR.EndOfStream
TextBox3.Text = TextBox3.Text & SR.ReadLine & vbCrLf
Loop
SR.Close()
End If
Dim data1 = IO.File.ReadLines(strtext).
Skip(2).
Select(Function(line)
Dim parts = line.Split(","c)
Return New RefTrans With {.Wavelength = CDbl(parts(0)),
.Transpercent = CDbl(parts(1))}
End Function).
ToArray() = line.Split(","c)
End Sub
End Class
Here's an example that will get you an array of Tuple(Of Double, Double):
Dim data = IO.File.ReadLines(filePath).
Skip(2).
Select(Function(line)
Dim parts = line.Split(","c)
Return Tuple.Create(CDbl(parts(0)), CDbl(parts(1)))
End Function).
ToArray()
The IO.File.ReadLines method will read the lines of the file. Where the ReadAllLines method reads the entire file and then returns the lines as a String array, the ReadLines method exposes the lines of the file as an enumerable list and the lines only get read from the file as you use them. Particularly for big files, ReadLines is more efficient than ReadAllLines because it does create an intermediate array first that you don't actually want.
The Skip method allows you to access the items in a list starting at a particular index. In the case of reading a file, you need to read every line regardless but call Skip(2) on the result of File.ReadLines means that the first two lines of the file will be discarded after reading and any subsequent processing will only but done on lines from the third.
The Select method is basically a transformation. It says create an output list containing an item for every item in the input list where the output item is the result of a transformation of the input item. The transformation is defined by the function you provide. In this case, a line from the file is the input and the transformation is to split that line on the comma, convert the two substrings to Double values and then create a Tuple containing those two Double values.
The ToArray method takes any enumerable list, i.e. any object that implements IEnumerable(Of T), and returns an array containing the items from that list. In this case, Select returns an IEnumerable(Of Tuple(Of Double, Double)) so ToArray returns a Tuple(Of Double, Double) array.
If you wanted to write that all out long-hand then it would look like this:
'Get all the lines of the file.
Dim step1 As IEnumerable(Of String) = IO.File.ReadLines(filePath)
'Skip the first two lines.
Dim step2 As IEnumerable(Of String) = step1.Skip(2)
'Split each line into two substrings.
Dim step3 As IEnumerable(Of String()) = step2.Select(Function(line) line.Split(","c))
'Convert substrings to numbers and combine.
Dim step4 As IEnumerable(Of Tuple(Of Double, Double)) = step3.Select(Function(parts) Tuple.Create(CDbl(parts(0)), CDbl(parts(1))))
'Create an array of Tuples.
Dim data As Tuple(Of Double, Double)() = step4.ToArray()
A Tuple is basically a general-purpose object for grouping values together. You can use a Tuple for one-off cases rather than defining your own class. You may prefer to define your own class in all cases though, and you should define your own class where you will use the data extensively. In this case, your own class might look like this:
Public Class RefTrans
Public Property Wavelength As Double
Public Property TransPercent As Double
End Class
and the code would then become:
Dim data = IO.File.ReadLines(filePath).
Skip(2).
Select(Function(line)
Dim parts = line.Split(","c)
Return New RefTrans With {.Wavelength = CDbl(parts(0)),
.TransPercent = CDbl(parts(1))}
End Function).
ToArray()
In that case, you have properties Wavelength and TransPercent on each element of your array. If you use Tuples then the properties have the generic names Item1 and Item2.
Once you have the array, you can use any appropriate overload of Array.Sort to do the sorting, e.g.
Array.Sort(data, Function(d1, d2) d1.Item1.CompareTo(d2.Item1))
That will sort the Tuples by comparing their Item1 properties, which contain the wavelength values. If you're using your own class then obviously you specify your own property, e.g. the Wavelength property in the RefTrans class I showed.

VB Import variable then use part 1 in dropdown and display part 2 to match selection in part 1

I'm using Visual studio to build a small utility.
I'm importing variables from a text file (this makes my program expandable in the future).
I'm running into a road block trying to split the variables into usable parts.
The text file is set up as such:
Game1:flshflhdlsfsdsfs
Game2:ugdjgndrgbdvdnjd
Game3:gnnereknengievke
And the code I've gathered from searching around trying to understand how I could do this is (It's gone through multiple rewrites but I feel this is probably the closest I've gotten):
Dim value As String = File.ReadAllText("Games.txt")
Dim cut_at As String = ":"
Dim x As Integer = InStr(value, cut_at)
Dim string_before As String = value.Substring(0, x - 2)
Dim string_after As String = value.Substring(x + cut_at.Length - 1)
Games_drp.Items.AddRange(string_before)
When I run a test like this, I get an error that String_before cannot be converted to an object. I tried switching "Dim string_before As String = value.Substring(0, x - 2)" to Dim string_before As Object = value.Substring(0, x - 2), but the dropdown that's supposed to be populated by at least one of the entries before the : has absolutely nothing in it.
Being pretty new at VB and feeling like I've exhausted pretty much every way I could think of searching in google and trying to piece together various bits of information, I figure I'd try asking my own direct question:
How would I go about reading all the lines from a text file, then splitting before the : to fill a combobox, and using a label to display the string after the : matching which ever entry is selected in the dropdown.
Thanks in advance for any help.
EDIT with full code:
Imports System.IO
Public Class Saves_frm
Private Sub Saves_frm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim value As String = File.ReadAllText("Games.txt")
Dim cut_at As String = ":"
Dim x As Integer = InStr(value, cut_at)
Dim string_before As String = value.Substring(0, x - 2)
Dim string_after As String = value.Substring(x + cut_at.Length - 1)
Games_drp.Items.AddRange(string_before)
End Sub
End Class
When run as is, I get an error that 'string_before' can't be converted from a string to an object, but when I make the following change from:
Dim string_before As String = value.Substring(0, x - 2)
to:
Dim string_before As Object = value.Substring(0, x - 2)
The error goes away, but the dropdown remains blank.
It's easier to use File.ReadAllLines, as it returns an array with all the file's lines. Then, you can loop through the lines, splitting each line and adding the result to the ListBox. This should be an example, but feel free to correct any mistakes I made, as I wrote it on my phone and it's been a long time since I used VB.
Dim lines() As String = File.ReadAllLines("file.txt")
For Each line As String In lines
Dim split() As String = line.Split(":"c)
gDic.Add(split(0), split(1))
Next
EDIT: Then, you most certainly want a dictionary that contains the name and the data, check the updated code.
Then, add the names by looping through gDic.Keys. When a name is selected, access its value with gDic("key").

search for phrase in line of text box vb.net

I'm using VB.NET and I've got a text box which contains the following information (that changes depending on the video file selected in a list box):-
type: ffmpeg-producer
filename: C:\caspar\Server\media\\adi.divx
width: 640
height: 360
progressive: false
fps: 25
loop: false
frame-number: 0
nb-frames: 4626
file-frame-number: 0
file-nb-frames: 4626
When I click a button, I need to add the data to a variable. So for example, I would need to take 4626 from the line
nb-frames: 4626
and 25 from the
line fps:25
and put them both in variables to then calculate the actual duration.
Public Function GetValue(ByVal varName As String) As String
Dim lines() As String = Split(TextBox1.Text, Delimiter:=Environment.NewLine)
For Each line As String In lines
Dim words() As String = Split(line, Delimiter:=": ", Limit:=2)
If words(0) = varName And words.Length = 2 Then
Return words(1)
End If
Next
Return Nothing
End Function
You could also use a regular expression approach. If you you are not familiar with regular expressions I strongly encourage you to into it.
Here is what you would do (where txtMyTextbbox is the textbox, that holds your data:
Dim strRegex as String = "([\w-]*):\s*(.*)"
Dim myRegex As New Regex(strRegex, RegexOptions.None)
Dim strTargetString As String = txtMyTextbox.Text
For Each myMatch As Match In myRegex.Matches(strTargetString)
If myMatch.Success Then
dim category = myMatch.Groups(1).Value
dim value = myMatch.Groups(2).Value
End If
Next
This code loops through all matches in your textbox text and looks for a text followed by a colon followed by spaces and the rest of the line. Each match is captured in the myMatch variable where you can access the part before the colon through myMatch.Groups(1).value and the part after the colon (excluding the space) through the second group.
Leave a comment if you have further questions.