reading from txt file and writing in textbox - vb.net

Can somebody help me with this, im stuck no idea what to do next
give a text file at any location in the computer it contains 15 different integers that can be repeated
make the program so that multiple repetitions of one number are not printed separately, but each number is printed exactly once
and next to it are written in which places he appeared
Imports System.IO
Public Class form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim povratnaVrijednost As DialogResult
Dim nazivDatoteke As String
Try
OpenFileDialog1.AddExtension = True
OpenFileDialog1.Multiselect = False
OpenFileDialog1.Filter = "Tekst datoteke (*.txt)|*.txt;"
povratnaVrijednost = OpenFileDialog1.ShowDialog()
If povratnaVrijednost = Windows.Forms.DialogResult.OK Then
If OpenFileDialog1.CheckFileExists = True And
OpenFileDialog1.CheckPathExists = True Then
nazivDatoteke = OpenFileDialog1.FileName
TextBox1.Text = nazivDatoteke
Dim citac As New StreamReader(nazivDatoteke)
Dim redTeksta As String = ""
Do
redTeksta = citac.ReadLine()
If Not redTeksta Is Nothing Then
RichTextBox1.Text = RichTextBox1.Text + redTeksta
End If
Loop Until redTeksta Is Nothing
citac.Close()
End If
End If
Catch ex As Exception
MsgBox("Greska prilikom otvaranja" + ex.StackTrace.ToString)
End Try
End Sub
End Class
123

Requirement #1:
give a text file at any location in the computer it contains 15 different integers that can be repeated
This requirement implies a couple of other requirements. First, you're expected to read the text file. Second, you're expected to parse the values into numbers (presumably integers).
You can use an OpenFileDialog (documentation) and specify that it can only accept text files:
Using browseFileDialog = New OpenFileDialog()
With browseFileDialog
.Filter = "*.txt|*.txt"
If (.ShowDialog() = DialogResult.Ok) Then
'.FileName will be the text file that the user picked
End If
End With
End Using
To read the text file, assuming you want each line, use the File.ReadAllLines method (documentation):
Using browseFileDialog = New OpenFileDialog()
With browseFileDialog
.Filter = "*.txt|*.txt"
If (.ShowDialog() = DialogResult.Ok) Then
Dim lines = IO.File.ReadAllLines(.FileName)
End If
End With
End Using
To parse the values, use the Array.ConvertAll method (documentation) and inside of the predicate use the Integer.Parse method (documentation):
Using browseFileDialog = New OpenFileDialog()
With browseFileDialog
.Filter = "*.txt|*.txt"
If (.ShowDialog() = DialogResult.Ok) Then
Dim lines = IO.File.ReadAllLines(.FileName)
Dim values = Array.ConvertAll(lines, Function(line) Integer.Parse(line))
End If
End With
End Using
Keep in mind that if you wanted to validate that the lines are all valid numbers, instead of assuming that they are, this step would be different. However, you didn't specify that requirement in your original post so I'm not including how to do that.
Requirement #2:
make the program so that multiple repetitions of one number are not printed separately, but each number is printed exactly once
You can use the Random.Next method (documentation) to generate random values. Be sure to declare the new instance of the random object once so that the seed is only set once. To randomly order the values, use the OrderBy method (documentation) passing the random value in the predicate:
Private ReadOnly _random As New Random()
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Using browseFileDialog = New OpenFileDialog()
With browseFileDialog
.Filter = "*.txt|*.txt"
If (.ShowDialog() = DialogResult.Ok) Then
Dim lines = IO.File.ReadAllLines(.FileName)
Dim values = Array.ConvertAll(lines, Function(line) Integer.Parse(line))
Dim randomlyOrderedValues = values.OrderBy(Function(value) _random.Next())
RichTextBox1.Text = String.Join(", ", randomlyOrderedValues.ToArray())
End If
End With
End Using
End Sub

Default for .AddExtension is True. Default for .Multiselect is False. I have simplified the If statement by comparing the return value of .Showdialog directly to the desired DialogResult. If the path of file don't exist the dialog will show a waring.
Always scope variables as narrowly as possible. I move the Dim nazivDatoteke to inside the If since it is not used anywhere else. StreamReaders require a Using block since they need to be disposed.
Why a RichTextBox for a text file?
As you can see getting the distince items in the array is easy, a single line of code. What is more difficult is finding the indexes in the original array, lines.
I looped through all the items in the distinct array (actually it is an IEnumerable(Of String) but that is not important to this code, it is just easier to type array in my explanation). I created a List(Of Integer) to hold the indexes of each item in the original array, lines. The startIndex where the FindIndex method of an Array is the location of the first occurrence of the String.
On each iteration of the Do loop I look for the matches to the item from the lines array. The FindIndex takes parameters (original array, index to start at, what we are looking for). It stops as soon as it finds a match and returns -1 if no matches are found. You can see the operation of this method be setting a break point and checking the variable values.
If a match is found I added that value to the list and change the startIndex to the position following the found index.
Next I used a StringBuilder to create the string to display. I chose the immediate window for testing purposes but you could show sb.ToString in a text box or add it to a ListBox.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
OpenFileDialog1.Filter = "Tekst datoteke (*.txt)|*.txt;"
If DialogResult.OK = OpenFileDialog1.ShowDialog Then
Dim nazivDatoteke = OpenFileDialog1.FileName
TextBox1.Text = nazivDatoteke
Dim lines = File.ReadAllLines(nazivDatoteke)
Dim distinct = lines.Distinct
For Each item In distinct
Dim lst As New List(Of Integer)
Dim startIndex = Array.IndexOf(lines, item)
Do
Dim FoundIndex = Array.FindIndex(lines, startIndex, Function(line) line = item)
If FoundIndex = -1 Then
Exit Do
Else
lst.Add(FoundIndex)
startIndex = FoundIndex + 1
End If
Loop
Dim sb As New StringBuilder
sb.Append(item)
For Each i In lst
sb.Append($" ({i})")
Next
Debug.Print(sb.ToString)
Next
End If
End Sub
This code displays the distinct items in the list and follow it with the positions (indexes) in the original list.

Related

Select random person from text file and change corresponding values

I have a form with a button and a label. I also have a text file with the following contents:
Bob:Available:None:0
Jack:Available:None:0
Harry:Available:None:0
Becky:Unavailable:Injured:8
Michael:Available:None:0
Steve:Available:None:0
Annie:Unavailable:Injured:12
Riley:Available:None:0
The values in the text file are:
person-name:available-or-unavailable:sick-or-injured:months-they-will-be-unavailable
What I would like to do is to have the user click the button and a random (available) person will be selected from the text file. The label's text will then say:
personname & " has gotten injured and will be unavailable for 10 months."
I would then like to overwrite the text file with the corresponding values for that particular person. For example that person's second value will now be "Unavailable", the third value will be "Injured" and the fourth value will be 10.
I hope this makes sense.
I don't have any code, as I literally have no idea how to do this. Any help would be much appreciated!
Explanations and code in line.
Private r As New Random
Private RandomIndex As Integer
Private dt As New DataTable
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
AddColumnsToDataTable()
FillDataTable()
End Sub
Private Sub AddColumnsToDataTable()
'Need to prepare the table to receive the data
dt.Columns.Add("Name")
dt.Columns.Add("Available")
dt.Columns.Add("Injury")
dt.Columns.Add("Months")
End Sub
Private Sub FillDataTable()
'ReadAllLines returns an array of lines in the text file
Dim lines = File.ReadAllLines("workers.txt")
'Loop through each line in the lines array
For Each line As String In lines
'.Split returns an array based on splitting the line
'by the colon. The c following ":" tells the compiler
'that this is a Char which the split function requires.
Dim items = line.Split(":"c)
'We can add a row to the data table all at once by
'passing in an array of objects.
'This consists of the elements of the items array
dt.Rows.Add(New Object() {items(0), items(1), items(2), items(3)})
Next
'Now we have an in memory DataTable that contains all the data from the text file.
End Sub
Private Function GetRandomWorker() As String
'A list of all the row indexes that are available
Dim AvailableList As New List(Of Integer)
For i As Integer = 0 To dt.Rows.Count - 1
'Loop through all the data in the date table row by row
If dt.Rows(i)("Available").ToString = "Available" Then
'Add only the row indexes that are Available
AvailableList.Add(i)
End If
Next
'Get a random index to use on the list of row indexes in IndexList
If AvailableList.Count = 0 Then
'No more workers left that are Available
Return ""
End If
'Get a random number to use as an index for the available list
Dim IndexForList = r.Next(AvailableList.Count)
'Selects a row index based on the random index in the list of Available
RandomIndex = AvailableList(IndexForList)
'Now use the index to get information from the row in the data table
Dim strName = dt.Rows(RandomIndex)("Name").ToString
Return strName
End Function
Private Sub SaveDataTable()
'Resave the whole file if this was a real app you would use a database
Dim sb As New StringBuilder
'A string builder keeps the code from creating lots of new strings
'Strings are immutable (can't be changed) so every time you think you are
'changing a string, you are actually creating a new one.
'The string builder is mutable (changable)
For Each row As DataRow In dt.Rows
'The ItemsArray returns an array of objects containing all the
'values in each column of the data table.
Dim rowValues = row.ItemArray
'This is a bit of Linq magic that turns the values into strings
Dim strRowValues = From s In rowValues
Select DirectCast(s, String)
'Now that we have strings we can use the String.Join with the colon
'to get the format of the text file
sb.AppendLine(String.Join(":", strRowValues))
Next
'Finally we change the StringBuilder to a real String
'The workers.txt is stored in the Bin\Debug directory so it is current directory
'no additional path required
File.WriteAllText("workers.txt", sb.ToString)
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
SaveDataTable()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim WorkerName As String = GetRandomWorker()
If WorkerName = "" Then
MessageBox.Show("There are no available workers")
Return
End If
Label1.Text = $"{WorkerName} has gotten injured and will be unavailable for 10 months."
dt.Rows(RandomIndex)("Available") = "Unavailable"
dt.Rows(RandomIndex)("Injury") = "Injured"
dt.Rows(RandomIndex)("Months") = "10"
End Sub

Read in values from comma delimited text file and add,create object of the class, then add objects to collection

I currently have the following code:
Public Class CPUForm
Dim myCPUList As New List(Of CPUClass)
Dim Counter As Integer = 0
Private Sub CPUForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
OpenFileDialog.ShowDialog()
Try
If IO.File.Exists(OpenFileDialog.FileName) = False Then
End If
Catch ex As IO.FileNotFoundException
MessageBox.Show("The File Could Not Be Found", "Alert")
End Try
If IO.File.Exists(OpenFileDialog.FileName) = True Then
Dim sr As IO.StreamReader = IO.File.OpenText(OpenFileDialog.FileName)
Dim line As Object
Dim data() As Object
Do Until sr.EndOfStream
line = sr.ReadLine
data = line.Split(",")
Dim ACpu As New CPUClass(data(0), data(1), data(2), data(3), data(4), data(5))
myCPUList(Counter) = ACpu
Counter += 1
Loop
sr.Close()
End If
lstOut.DataSource = Nothing
lstOut.DataSource = myCPUList
End Sub
End Class
The goal here is to read-in values from a comma separated text file, create objects of the class, add those objects to the collection, and then display the collection in a listbox using an overridden ToString method.
Right now I get no errors, even at runtime. The problem is that one the file is selected, nothing happens. Nothing is displayed in the listbox as if nothing was added to the collection. Also, an overloaded constructor exists to receive the values being read in.
Turns out the code is fine, the problem was an out of place comma in the text file.

Md5 hash entire listbox

As of now I can hash listbox selected item with
Public Function Md5FromString(ByVal Source As String) As String
Dim Bytes() As Byte
Dim sb As New StringBuilder()
'Check for empty string.
If String.IsNullOrEmpty(Source) Then
Throw New ArgumentNullException
End If
'Get bytes from string.
Bytes = Encoding.Default.GetBytes(Source)
'Get md5 hash
Bytes = MD5.Create().ComputeHash(Bytes)
'Loop though the byte array and convert each byte to hex.
For x As Integer = 0 To Bytes.Length - 1
sb.Append(Bytes(x).ToString("x2"))
On Error Resume Next
Next
'Return md5 hash.
Return sb.ToString()
End Function
And collect them in another listbox, but I get an error (An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll) after about 4K somewhere random as if it fails to update a label or textbox then have to edit my list and reset and i just feel there is a better way to do this.
Can someone more experienced offer some guidance in making this routine more efficient?
Not sure where your error is coming from, but you definitely don't need to be using Create() in a tight loop. Store it as a local variable and re-use it by declaring it as static (or keep the reference at class level instead):
Public Function Md5FromString(ByVal Source As String) As String
Static local_MD5 As MD5 = MD5.Create
If String.IsNullOrEmpty(Source) Then
Throw New ArgumentNullException
End If
Dim sb As New StringBuilder()
For Each b As Byte In local_MD5.ComputeHash(Encoding.Default.GetBytes(Source))
sb.Append(b.ToString("x2"))
Next
Return sb.ToString()
End Function
Ok, here is how I figured out to work better than what I was doing by a tremendous bound, I was waiting for about an hour for 4K hashes now I get 50K in mins by hashing the string as they come in from the .txt. May still be messy but it works way faster.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = ""
OpenFileDialog1.Title = "Please Select a File"
OpenFileDialog1.InitialDirectory = "C:temp"
OpenFileDialog1.ShowDialog()
Dim path As String = OpenFileDialog1.FileName
TextBox1.Text = path
Dim lines() As String = IO.File.ReadAllLines(TextBox1.Text)
For Each line In lines
ListBox1.Items.Add(Md5FromString(line) + ":" + line)
ListBox1.Refresh()
Label1.Text = ListBox1.Items.Count
Label1.Refresh()
If ListBox1.Items.Count = 1000 Then
save()
ListBox1.Items.Clear()
ListBox1.Refresh()
Label1.Text = 0
End If
Next
' ListBox1.SelectedIndex = 0
End Sub

Advanced Replacement Freeze

Basically I'm creating a tool which while is looking through lines of "file.txt" to replace a word from a textbox's content with that line if the line is containing that word.
Basically if the line is: pizza-cheese-potatoes, all the words containing "pizza" or "cheese" or "potatoes" to be replaced with "pizza-cheese-potatoes"
Here is what I have until now. But it freeze and I don't really know why. Please help me. :)
Dim PATH As String = "C:\test.txt"
Sub Repl(x As String)
For Each line As String In File.ReadLines(PATH)
Dim myList = New List(Of String)(line.Split("|"c))
For Each item As String In myList
If x Is item Then
TextBox1.Text.Replace(x, line)
End If
Next
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each word As String In TextBox1.Text.Split(" "c)
Repl(word)
Next
End Sub
Thank you in advance!
Try doing it like this instead.
Public Sub DoWork()
Dim lines = IO.File.ReadAllLines(PATH)
For Each line In lines
Dim myList = New List(Of String)(line.Split("-"c))
For Each item In myList
If TextBox1.Text.Contains(item) Then
TextBox1.Text = TextBox1.Text.Replace(item, line)
End If
Next
Next
End Sub
Your reader reads the file multiple times which is massively inefficient. This code reads it once, then we just loop over each line with no need to worry about exit conditions etc.
However it's not really doing anything useful as you're not pausing after each line so you'll only be able to review the final one.
There is also no need to test if the textbox contains the text, just simply do a replace then you only search the text once.
For Each item In myList
TextBox1.Text = TextBox1.Text.Replace(item, line)
Next
-------- edit --------
To fix the issue with replacing the word you've already replaced you could try using a replacement placeholder.
For Each item In myList
TextBox1.Text = TextBox1.Text.Replace(item, "#")
Next
TextBox1.Text = TextBox1.Text.Replace("#", line)
---------- edit 2 ------------------
You want to try and build up a new string, word by word, instead of replacing the text in the textbox. This is so that words you've substituted already don't get converted.
Function ReplaceWord(word As String, lines As String())
For Each line As String In File.ReadLines(PATH)
Dim myList = New List(Of String)(line.Split("|"c))
For Each item As String In myList
If word = item Then
Return line
End If
Next
Next
Return word
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim result As New System.Text.StringBuilder
Dim lines = File.ReadLines(PATH)
For Each word As String In TextBox1.Text
result.Append(ReplaceWord(word, lines)).Append(" ")
Next
Textbox1.Text = result.ToString()
End Sub

Importing a CSV into a combobox, then changing other things in VB

What I want to do is import a CSV file (called fwlist.txt), that looks like this:
modelname,power type,pic,part number,firmware, option1, option 1, etc
End result, i would like a combobox that shows the modelname, and when the model name is selected from the pulldown, it updates various labels and text boxes on the form with other information.
Here's what I have so far:
Dim filename As String = "fwlist.txt"
Dim pwrtype As String
Dim pic As String
Dim partnum As String
Dim lineread As String
Dim FirmwareName As String
Private Sub ReadFirmwaresLoad(sender As Object, e As EventArgs) Handles Me.Load
' Load the items into the NameComboBox list.
Dim ResponseDialogResult As DialogResult
Try
Dim FirmwareStreamReader As StreamReader = New StreamReader(filename)
' Read all the elements into the list.
Do Until FirmwareStreamReader.Peek = -1
lineread = FirmwareStreamReader.ReadLine()
Dim fields As String() = lineread.Split(",")
FirmwareName = fields(0) 'Take First Field
cbFW.Items.Add(FirmwareName)
'Set Text labels based on position in line.
pwrtype = fields(1)
pic = fields(2)
partnum = fields(3)
(...etc through options)
Loop
' Close the file.
FirmwareStreamReader.Close()
Catch ex As Exception
' File missing.
ResponseDialogResult = MessageBox.Show("File not Found!", "File Not Found",
MessageBoxButtons.OK, MessageBoxIcon.Question)
If ResponseDialogResult = DialogResult.OK Then
' Exit the program.
Me.Close()
End If
End Try
End Sub
Private Sub cbFW_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbFW.SelectedIndexChanged
lblPwrType.Text = pwrtype
lblPic.Text = pic
lblPartNum.Text = parnum
....etc thruogh options
End Sub
This code works, but only sort of. If i select anything from the combo box, it only gives me the information from the very last line of the CSV file - even if its the first entry in the box. I'm pretty sure it's something simple that I'm messing up.. anyone help?
First we read the lines into Firmware objects then we set this List(Of Firmware) as the DataSource of the ComboBox.
Then we handle the SelectedIndexChanged event of the ComboBox which will get the currently selected firmware and loads its data to the TextBox controls.
This is a tested, working example below:
Public Class Firmware
Public Property ModelName As String
Public Property PowerType As String
Public Property Pic As String
Public Property PartNumber As String
Public Property Firmware As String
Public Property Option1 As String
End Class
Public Class MainForm
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
Dim lines As String() = Nothing
Try
' Read the file in one step
lines = File.ReadAllLines("fwlist.txt")
Catch ex As Exception
Dim dialogResult As DialogResult = MessageBox.Show(Me, "File not found! Would you like to exit program?", "Error reading file", MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button2)
If dialogResult = DialogResult.Yes Then
Me.Close()
End If
Exit Sub
End Try
Dim firmwares As List(Of Firmware) = New List(Of Firmware)
For Each line As String In lines
Dim rawData As String() = line.Split({","}, StringSplitOptions.None)
' Create Firmware object from each line
Dim firmware As Firmware = New Firmware() With
{
.ModelName = rawData(0),
.PowerType = rawData(1),
.Pic = rawData(2),
.PartNumber = rawData(3),
.Firmware = rawData(4),
.Option1 = rawData(5)
}
' We store the read firmwares into a list
firmwares.Add(firmware)
Next
' Set the list as the data source of the combobox
' DisplayMember indicates which property will be shown in the combobox
With cboModelNames
.DataSource = firmwares
.DisplayMember = "ModelName"
End With
End Sub
Private Sub cboModelNames_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboModelNames.SelectedIndexChanged
RefreshForm()
End Sub
Private Sub RefreshForm()
' Get the selected item as Firmware object
Dim currentFirmware As Firmware = DirectCast(cboModelNames.SelectedItem, Firmware)
' Refresh all the textboxes with the information
With currentFirmware
txtPowerType.Text = .PowerType
txtPic.Text = .Pic
txtPartNumber.Text = .PartNumber
txtFirmware.Text = .Firmware
txtOption1.Text = .Option1
End With
End Sub
End Class
Every time you set the value of a variable like pwrtype, its old value is thrown away and there is no way to get it back. And even if you did save multiple values for each variable, you would need a way to figure out which value goes with the currently selected item in the combo box. To resolve these two issues you need:
a way to group values from the same line together
a way to save all values read from the file, not just the most recent ones
Let's start with the first issue, grouping values together. In the example code below, I created a Structure type called FirmwareInfo to serve that purpose. Each FirmwareInfo has its own pwrtype, pic, etc.
The other piece of the puzzle that you are missing is a way to save more than one Firmware. The easiest way to do this is to add each FirmwareInfo to the combo box's item list, instead of adding just the display string. The combo box will convert each item to a string in the UI; the ToString() method tells it how you want this conversion to be done.
I haven't run this example code so I can't guarantee there aren't mistakes in there, but hopefully it's enough to show the general idea.
Dim filename As String = "fwlist.txt"
Structure FirmwareInfo
Public pwrtype As String
Public pic As String
Public partnum As String
Public FirmwareName As String
Public Overrides Function ToString() As String
Return FirmwareName
End Function
End Structure
Private Sub ReadFirmwaresLoad(sender As Object, e As EventArgs) Handles Me.Load
' Load the items into the NameComboBox list.
Dim ResponseDialogResult As DialogResult
Try
Dim FirmwareStreamReader As StreamReader = New StreamReader(filename)
' Read all the elements into the list.
Do Until FirmwareStreamReader.Peek = -1
Dim lineread = FirmwareStreamReader.ReadLine()
Dim fields As String() = lineread.Split(",")
Dim info As New FirmwareInfo With {
.FirmwareName = fields(0),
.pwrtype = fields(1),
.pic = fields(2),
.partnum = fields(3)
}
cbFW.Items.Add(info)
Loop
' Close the file.
FirmwareStreamReader.Close()
Catch ex As Exception
' File missing.
ResponseDialogResult = MessageBox.Show("File not Found!", "File Not Found",
MessageBoxButtons.OK, MessageBoxIcon.Question)
If ResponseDialogResult = DialogResult.OK Then
' Exit the program.
Me.Close()
End If
End Try
End Sub
Private Sub cbFW_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbFW.SelectedIndexChanged
Dim currentInfo = DirectCast(cbFW.SelectedItem, FirmwareInfo)
lblPwrType.Text = currentInfo.pwrtype
lblPic.Text = currentInfo.pic
lblPartNum.Text = currentInfo.parnum
' ....etc through options
End Sub