VB.net multithreading for loop, parallel threads - vb.net

I have a simple form with 2 RichTextBoxes and 1 button, the code grabs the url address from RichTextBox1 and phrases the page for the title field using regex and appends it to RichTextBox2. I want to multithread everything in such way that none of the url's are skipped and the thread numbers can be set ( according to the system free resources ) For example, let's say 10 threads to run in parallel. I searched everything and the best that I managed to do is run everything in a background worker and keep the GUI from freezing while working. A short code sample will be of much help, I am a beginner in VB.net.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i = 0 To RichTextBox1.Lines.Length - 1
If RichTextBox1.Lines(i).Contains("http://") Then
Dim html As String = New System.Net.WebClient() _
.DownloadString(RichTextBox1.Lines(i))
Dim pattern As String = "(?<=\<title\>)([^<]+?)(?=\</title\>)"
Dim match As System.Text.RegularExpressions.Match = _
System.Text.RegularExpressions.Regex.Match(html, pattern)
Dim title As String = match.Value
RichTextBox2.AppendText(title & vbCrLf)
End If
Next
End Sub
End Class
Updated code ( throwing "Index was outside the bounds of the array." errors. )
Imports System
Imports System.Threading
Public Class Form1
Public Sub test(ByVal val1 As String, ByVal val2 As String)
Dim zrow As String
zrow = RichTextBox1.Lines(val1)
If zrow.Contains("http://") Then
Dim html As String = New System.Net.WebClient().DownloadString(zrow)
Dim pattern As String = "(?<=\<title\>)([^<]+?)(?=\</title\>)"
Dim match As System.Text.RegularExpressions.Match = System.Text.RegularExpressions.Regex.Match(html, pattern)
Dim title As String = match.Value
RichTextBox2.AppendText(val2 & title & vbCrLf)
End If
End Sub
Public Sub lastfor(ByVal number)
Dim start As Integer = number - 100
For x = start To number - 1
Try
test(x, x)
RichTextBox2.AppendText(x & RichTextBox1.Lines(x).Trim & vbCrLf)
Catch ex As Exception
'MsgBox(ex.Message)
RichTextBox3.AppendText(ex.Message & vbCrLf & vbCrLf)
End Try
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Control.CheckForIllegalCrossThreadCalls = False
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim TotalLines As String = RichTextBox1.Lines.Length - 1
Dim TotalThreads As Integer = 10
Dim LinesPerThread As Integer = TotalLines / TotalThreads
Dim increment As String = LinesPerThread
Dim zdata(TotalThreads) As String
For i = 0 To TotalThreads - 1
zdata(i) = increment
increment = increment + LinesPerThread
Next
Dim lst As New List(Of Threading.Thread)
For Each bump As String In zdata
Dim t As New Threading.Thread(Function(l As String)
'Do something with l
'Update GUI like this:
If bump = String.Empty Or bump Is Nothing Then
Else
lastfor(l)
'MsgBox(l)
End If
End Function)
lst.Add(t)
t.Start(bump)
Next
'test(1)
End Sub
End Class

There are two ways two achieve this:
First, if you are using .NET 4.0, you could use a Parallel.ForEach loop:
Parallel.ForEach(RichTextBox1.Lines, Function(line As String)
' Do something here
' To update the GUI use:
Me.Invoke(Sub()
' Update GUI like this...
End Sub)
Return Nothing
End Function)
The other way is to do this manually (and you will have slightly more control):
Dim lst As New List(Of Threading.Thread)
For Each line In RichTextBox1.Lines
Dim t As New Threading.Thread(Function(l As String)
'Do something with l
'Update GUI like this:
Me.Invoke(Sub()
'Update Gui...
End Sub)
End Function)
lst.Add(t)
t.Start(line)
Next
Both of these are very crude, but will get the job done.
EDIT:
Here is a sample code that will control the number of threads:
Dim lst As New List(Of Threading.Thread)
Dim n As Integer = 1 ' Number of threads.
Dim npl As Integer = RichTextBox1.Lines / n
Dim seg As New List(Of String)
For Each line In RichTextBox1.Lines
For i = npl - n To npl
seg.Add(RichTextBox1.Lines.Item(i))
Next
Dim t As New Threading.Thread(Function(l As String())
For Each lin In l
' TO-DO...
Next
'Do something with l
'Update GUI like this:
Me.Invoke(Sub()
'Update Gui...
End Sub)
End Function)
lst.Add(t)
t.Start(seg.ToArray())
Next
*The above code might have bugs.

Related

How to get line number from a text file in vb.net

I am making a program where i have 2 text files and i want 2 get one line from each text file like this
Dim pathlocal as string= Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\Test\"
Dim reader As New System.IO.StreamReader(pathlocal & "to.txt")
Dim allLines As List(Of String) = New List(Of String)
Do While Not reader.EndOfStream
allLines.Add(reader.ReadLine())
Loop
reader.Close()
For Each file In allLines
If pathlocal & "from.txt".Contains(My.Computer.FileSystem.GetFileInfo(file).Name) Then
'Get line number of from.txt where you found file.name
End If
End If
Next
I appreciate the help(and pls try 2 make it simple sorry but i am not that good THANX)
This might help you:
Imports System.IO
Imports System
Imports System.Collections.Generic
Public Class Form1
Dim path As String = "Your Path"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim indxto As Integer = 0
Dim indxfrom As Integer = 0
Dim allLinesto As List(Of String) = File.ReadAllLines(path & "\" & "to.txt").ToList
Dim allLinesfrom As List(Of String) = File.ReadAllLines(path & "\" & "from.txt").ToList
For Each line As String In allLinesto
indxto = allLinesto.IndexOf(line)
'Debug.Print(line & " " & indxto.ToString)
For Each item As String In allLinesfrom
indxfrom = allLinesto.IndexOf(item)
If line = item Then
Debug.Print(item & " " & indxfrom.ToString)
End If
Next
Next
End Sub
End Class
You can instantiate a couple of Integer typed variables to help with this. One stores the line number as you iterate through the list and the other stores the line number you are seeking. Plus, by changing your For Each approach to a Do Until or Do While approach you could potentially speed things up if the target is found prior to the last line of the file.
Dim intLineNumber As Integer = -1
Dim intLineCursor As Integer
Do Until (intLineCursor = allLines.Count OrElse intLineNumber <> -1)
If pathlocal & "from.txt".Contains(My.Computer.FileSystem.GetFileInfo(allLines(intLineCursor)).Name) Then
intLineNumber = intLineCursor '+ 1 if you are displaying to a user since the lower bound is 0 based.
End If
'Increment the cursor variable.
intLineCursor += 1
Loop

Multithreading duplicate error after background worker added

I wrote a program that does queries on some search engines that I wanted to be multithreaded so it could do the searches faster. I made a question about this which was answered indirectly, but I have yet another problem even after I set up delegates and such.
I was running the queries on the main thread, so I had to set up a BackgroundWorker. I did that but even though everything seems to run without an issue, I get duplicates of my results even though the program is suppose to do the opposite. Sometimes it doesn't even read or output a result that I know would be good.
Imports System.Net
Imports System.IO
Imports System.ComponentModel
Public Class Form2
Dim i As Integer
Dim SearchString As String
Public CleanSearchStrings As String()
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
i = RichTextBox1.Lines.Count
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub StartThreads()
While i > 0
i = i - 1
Dim thread_count As String = Process.GetCurrentProcess().Threads.Count - 20
Label_T(thread_count)
SearchString = LineFunc(i)
Threading.Thread.Sleep(500)
SearchString = Ask_Query(SearchString) #This was commented out
SearchString = Bing_Query(SearchString) #just simple webscraping
SearchString = Yahoo_Query(SearchString)
If SearchString.Contains("All_Query:Yes") Then
SearchString = SearchString.Replace("All_Query:Yes", "")
RTB(SearchString)
End If
End While
End Sub
Private Delegate Sub UpdateStatus(ByVal s As String)
Private Delegate Sub UpdateLabel(ByVal thread_count As String)
Private Delegate Function Line(ByVal i As Integer)
Function LineFunc(ByVal i As Integer)
If Me.InvokeRequired Then
Me.Invoke(New Line(AddressOf LineFunc), New Object() {i})
Else
SearchString = RichTextBox1.Lines(i).ToString
Return SearchString
End If
End Function
Sub RTB(ByVal s As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateStatus(AddressOf RTB), New Object() {s})
Else
RichTextBox2.AppendText(Environment.NewLine & s)
End If
End Sub
Sub Label_T(ByVal thread_count As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateLabel(AddressOf Label_T), New Object() {thread_count})
Else
Label3.Text = "Threads Running: " + thread_count
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.WorkerReportsProgress = True
Dim count As Integer
Dim num As Integer = TextBox1.Text - 1
For count = 0 To num
Dim thread = New Threading.Thread(AddressOf StartThreads)
thread.IsBackground = True
thread.Start()
Threading.Thread.Sleep(500)
Next
End Sub
End Class
I know it has something to do with the LineFunc that I wrote but I can't seem to figure it out.
This was working flawlessly on multithreading, but the UI would be frozen and after I added the BackgroundWorker it seems to be giving me these duplicate results error and not reading the TextBox fully.
Update:
Private Sub StartThreads()
For count = count To i
Dim SearchString As String = LineFunc(count)
count += 1
Dim thread_count As String = CType(Process.GetCurrentProcess().Threads.Count - 20, String)
Label_T(thread_count)
Threading.Thread.Sleep(500)
SearchString = CType(Ask_Query(SearchString), String)
SearchString = CType(Bing_Query(SearchString), String)
SearchString = CType(Yahoo_Query(SearchString), String)
If SearchString.Contains("All_Query:Yes") Then
SearchString = SearchString.Replace("All_Query:Yes", "")
RTB(SearchString)
End If
Next
End Sub
Heres my Revised Get Line Func
Private Delegate Function GetTextBox(ByVal index As Integer) As String
Public Function LineFunc(ByVal index As Integer) As String
If Me.InvokeRequired Then
Me.Invoke(New GetTextBox(AddressOf LineFunc), New Object() {index})
Else
Dim indexSearchString As String
indexSearchString = CType(RichTextBox1.Lines(index), String)
Return indexSearchString
End If
End Function
If i use the a msgbox it gives me the right values i don't understand how come it does not give me the right values when i do the func Dim SearchString As String = LineFunc(count) it returns a null string in the end i don't understand why
this seemed to work for the duplicate issue but now i seem to be having issues with my output to richtextbox2 only outputing blanks and the line func is only giving out blanks i don't understand why either but atleast there is progress
I can't verify if this will work as you haven't posted the search functions, but here goes.
Public Class Form2
Dim i As Integer
Dim SearchString As String
Dim ResultString As String
Public CleanSearchStrings As String()
Private threadCount As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SearchUsingRTB1Items()
End Sub
Private Sub SearchUsingRTB1Items()
threadCount = 0
Dim rtb1Lines() As String = RichTextBox1.Lines
Parallel.ForEach(rtb1Lines, Sub(line As String)
dim ResultString As String =""
threadCount += 1
Label_T(i.ToString)
ResultString =Ask_Query(line) 'This was commented out
ResultString = ResultString & Bing_Query(line) 'just simple webscraping
ResultString = ResultString & Yahoo_Query(line)
If ResultString.Contains("All_Query:Yes") Then
ResultString = ResultString.Replace("All_Query:Yes", "")
RTB(ResultString)
End If
threadCount -= 1
Label_T(i.ToString)
End Sub)
End Sub
Private Delegate Sub UpdateStatus(ByVal s As String)
Private Delegate Sub UpdateLabel(ByVal thread_count As String)
Sub RTB(ByVal s As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateStatus(AddressOf RTB), New Object() {s})
Else
RichTextBox2.AppendText(Environment.NewLine & s)
End If
End Sub
Sub Label_T(ByVal thread_count As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateLabel(AddressOf Label_T), New Object() {thread_count})
Else
Label3.Text = "Threads Running: " & thread_count
End If
End Sub
End Class

looping to add 271 records into my dictionary it only add 150 then exit the subroutine. (VB.net 2015)

For VB.net 2015
I'm a new programmer. I've been warping my brain around this for 2 days. Can seem to see the problem. It seems I can only add 150 records to the dictionary. I'm not sure where its failing in the code. I'm not getting any errors or warnings.
Really hope someone can give me a hand.
Heres a link to my file I'm working with.
https://drive.google.com/file/d/0B1zf86jcRv49Y1lCMHRvNWt4UFk/view?usp=sharing
P.S. Sry about the crappy coding skill :-)
Imports System
Imports System.IO
Public Class Form1
Dim xx As Integer = 0
Private MainDataList As New Dictionary(Of String, List(Of String))
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim temp1 As List(Of String)
'MsgBox(xx)
If MainDataList.ContainsKey(TextBox1.Text) Then
temp1 = MainDataList.Item(TextBox1.Text)
Label1.Text = temp1(0)
Beep()
Else
Label1.Text = "Not Found"
Beep()
Beep()
End If
TextBox1.Text = ""
End Sub
Private Sub GetData()
Dim ReadDataLine(50000) As String
Try
' Open the file using a stream reader.
Using sr As New StreamReader("C:\Inventory\Invatory.csv")
'Dim line As String
' Read the stream to a string and write the string to the console.
ReadDataLine(0) = sr.ReadLine
Do While (sr.EndOfStream = False)
ReadDataLine(xx) = sr.ReadLine
'AddToList(ReadDataLine) ' pars data into main list
'MsgBox(sr.ReadLine)
xx = xx + 1
Loop
sr.Close()
'line = sr.ReadLine()
End Using
Catch e As Exception
'MsgBox(xx)
MsgBox("The file could not be read:")
MsgBox(e.Message)
End Try
'MsgBox(xx)
'xx = 0
For Each i As String In ReadDataLine
AddToList(i)
'MsgBox(xx)
'xx = xx + 1
Next
End Sub
Private Sub AddToList(data As String)
Dim barCode As String = ""
Dim steps As Integer = 1
Dim LastPos As Integer = 2
Dim datalist As New List(Of String)
Dim firstPass As Boolean = False
For i = 2 To Len(data)
'Find end of cell
If Mid(data, i, 1) = "," Then
If firstPass = False Then
barCode = Mid(data, LastPos, i - 2)
'MsgBox(Mid(data, LastPos, i - 2))
LastPos = i
firstPass = True
Else
Dim temp As Integer = i - LastPos
datalist.Add(Mid(data, LastPos + 1, temp - 1))
'MsgBox(Mid(data, LastPos + 1, temp - 1))
LastPos = i
End If
End If
Next
MainDataList.Add(barCode, datalist)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
GetData()
Label1.Text = "Ready!"
Me.Show()
TextBox1.Focus()
End Sub
Private Sub Label1_Click(sender As Object, e As EventArgs) Handles Label1.Click
End Sub
End Class

FOR statement conflicting with IF statement in VB

I am creating a fairly simple ping tool which shows in milliseconds how long the server took to respond. If the server does not respond, it shows as it responded in 0ms. I wanted to implement an If statement to write Server failed to respond in the ListBox rather than it replied in 0ms. The only problem with this is I have a chunk of code which need to be run outside the If but continues inside the If and involves using the line of code Next... This seems to cause the If statement to not recognise the End If and the End If to not recognise the If...
Here is my code:
For i As Integer = 0 To numberOfPings - 1
Dim ping As New Ping
Dim pingRe As PingReply = ping.Send(pingTarget)
If pingRe.RoundtripTime = 0 Then
Me.listboxPing.Items.Add("Server failed to respond...")
Else
Me.listboxPing.Items.Add("Response from " & pingTarget & " in " & pingRe.RoundtripTime.ToString() & "ms")
listboxPing.SelectedIndex = listboxPing.Items.Count - 1
listboxPing.SelectedIndex = -1
Application.DoEvents()
Threading.Thread.Sleep(500)
Next
Me.listboxPing.Items.Add("")
End If
Does anyone know of a way I could fix this/get around this issue?
Thanks,
If I were going to write code to ping an address and show the results it would look something like this.
Dim pingThrd As Threading.Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If pingThrd Is Nothing OrElse pingThrd.ThreadState = Threading.ThreadState.Stopped Then
RichTextBox1.Clear()
pingThrd = New Threading.Thread(AddressOf PingIt)
pingThrd.IsBackground = True
pingThrd.Start("192.168.33.1")
End If
End Sub
Public Sub PingIt(pingTarget As Object)
Dim numberOfPings As Integer = 5
Dim pingT As String = DirectCast(pingTarget, String)
Dim pingTimeOut As Integer = 1000
Const dlyBetweenPing As Integer = 500
Dim dspStr As String
For i As Integer = 0 To numberOfPings - 1
Dim pingit As New Ping
Dim pingRe As PingReply = pingit.Send(pingT, pingTimeOut)
'check if success
If pingRe.Status = IPStatus.Success Then
dspStr = String.Format("Response from: {0} in {1}ms.", pingRe.Address, pingRe.RoundtripTime)
Else
dspStr = String.Format("{0} failed. Status: {1}", pingRe.Address, pingRe.Status)
End If
Me.BeginInvoke(Sub()
RichTextBox1.AppendText(dspStr)
RichTextBox1.AppendText(Environment.NewLine)
End Sub)
Threading.Thread.Sleep(dlyBetweenPing)
Next
End Sub
edit: Same basic code but allow thread to start with different address and count.
Structure PingWhat
Dim addr As String
Dim howmany As Integer
End Structure
Dim pingThrd As Threading.Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If pingThrd Is Nothing OrElse pingThrd.ThreadState = Threading.ThreadState.Stopped Then
RichTextBox1.Clear()
'setup a thread to do the actual ping'ing
'this allows the UI to function
pingThrd = New Threading.Thread(AddressOf PingIt)
pingThrd.IsBackground = True
'setup address to ping and howmany times to ping it
Dim somePing As New PingWhat With {.addr = "192.168.33.1", .howmany = 3}
'start the thread
pingThrd.Start(somePing)
End If
End Sub
Public Sub PingIt(pingTarget As Object)
Dim pingT As PingWhat = DirectCast(pingTarget, PingWhat)
Dim pingTimeOut As Integer = 1000
Const dlyBetweenPing As Integer = 500
Dim dspStr As String
For i As Integer = 1 To pingT.howmany
Dim pingit As New Ping
Dim pingRe As PingReply = pingit.Send(pingT.addr, pingTimeOut)
'check if success
If pingRe.Status = IPStatus.Success Then
dspStr = String.Format("Response from: {0} in {1} ms.", pingRe.Address, pingRe.RoundtripTime)
Else
dspStr = String.Format("Ping Failed {0}. Status: {1}", pingT.addr, pingRe.Status)
End If
'update the UI
Me.BeginInvoke(Sub()
RichTextBox1.AppendText(dspStr)
RichTextBox1.AppendText(Environment.NewLine)
RichTextBox1.ScrollToCaret()
End Sub)
Threading.Thread.Sleep(dlyBetweenPing)
Next
Me.BeginInvoke(Sub()
RichTextBox1.AppendText("Done")
RichTextBox1.AppendText(Environment.NewLine)
RichTextBox1.ScrollToCaret()
End Sub)
End Sub
Is this what you're after?
For i As Integer = 0 To numberOfPings - 1
Dim ping As New Ping
Dim pingRe As PingReply = ping.Send(pingTarget)
If pingRe.RoundtripTime = 0 Then
Me.listboxPing.Items.Add("Server failed to respond...")
Else
Me.listboxPing.Items.Add("Response from " & pingTarget & " in " & pingRe.RoundtripTime.ToString() & "ms")
listboxPing.SelectedIndex = listboxPing.Items.Count - 1
listboxPing.SelectedIndex = -1
Application.DoEvents()
Threading.Thread.Sleep(500)
add = True
Exit For
End If
Next
If add Then Me.listboxPing.Items.Add("")
The If will change the scope, therefore, you need to use a variable to check whether it went into the Else part.
Of course, you need to close the first If before the Next.
#dbasnett This was the code I using before and it was absolutely perfect for what i needed EXCEPT if a ping failed it would just say (PingTarget) responded in 0ms which is not ideal. Ideally i would like it to say Server failed to respond... . Do you know a way in which this can be achieved by modifying my original code?
Imports System.Net.NetworkInformation
Imports System.Runtime.InteropServices
Public Class PingClient
Private Const EM_SETCUEBANNER As Integer = &H1501
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As String) As Int32
End Function
Private Sub SetCueText(ByVal control As Control, ByVal text As String)
SendMessage(control.Handle, EM_SETCUEBANNER, 0, text)
End Sub
Private Sub PingClient_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SetCueText(textboxIP, "IP Address/Domain")
SetCueText(textboxPing, "No. Of Pings")
End Sub
Structure PingWhat
Dim addr As String
Dim howmany As Integer
End Structure
Dim pingThrd As Threading.Thread
Public Sub buttonPing_Click(sender As Object, e As EventArgs) Handles buttonPing.Click
If pingThrd Is Nothing OrElse pingThrd.ThreadState = Threading.ThreadState.Stopped Then
Dim pingTarget As String = ""
Dim numberOfPings As Integer = 0
Dim intTimeout As Integer = 2000
If String.IsNullOrEmpty(textboxIP.Text) Then
MsgBox("You must enter an IP Address or Domain.")
Exit Sub
End If
If Not Int32.TryParse(textboxPing.Text, numberOfPings) Then
MsgBox("You must enter a number of how many times the target address will be pinged.")
Exit Sub
End If
If numberOfPings = 0 Then
MsgBox("You must enter a value over 0.")
textboxPing.Clear()
Exit Sub
End If
'setup a thread to do the actual ping'ing
'this allows the UI to function
pingThrd = New Threading.Thread(AddressOf PingIt)
pingThrd.IsBackground = True
'setup address to ping and howmany times to ping it
Dim somePing As New PingWhat With {.addr = pingTarget, .howmany = numberOfPings}
'start the thread
pingThrd.Start(somePing)
End If
Me.listboxPing.Items.Add("")
End Sub
Public Sub PingIt(pingTarget As Object)
Dim pingT As PingWhat = DirectCast(pingTarget, PingWhat)
Dim pingTimeOut As Integer = 1000
Const dlyBetweenPing As Integer = 500
Dim dspStr As String
For i As Integer = 1 To pingT.howmany
Dim pingit As New Ping
Dim pingRe As PingReply = pingit.Send(pingT.addr, pingTimeOut)
'check if success
If pingRe.Status = IPStatus.Success Then
dspStr = String.Format("Response from: {0} in {1} ms.", pingRe.Address, pingRe.RoundtripTime)
Else
dspStr = String.Format("Ping Failed {0}. Status: {1}", pingT.addr, pingRe.Status)
End If
'update the UI
Me.BeginInvoke(Sub()
listboxPing.Items.Add(dspStr)
End Sub)
Threading.Thread.Sleep(dlyBetweenPing)
Next
Me.BeginInvoke(Sub()
listboxPing.Items.Add("Done")
End Sub)
End Sub
Private Sub PingClient_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
Dim Response As Integer
Response = MsgBox("Are you sure you want to exit the Ping Tool?", 36)
If Response = MsgBoxResult.Yes Then
Else
e.Cancel = True
End If
End Sub
End Class

How to read a specific line from a text file in VB

I am creating a program that is supposed to write text into a text file, and should be able to read specific lines from a text file in VB (so if i needed to read a specific name I could select line 5 and it would display in the textbox). I am able to read the text from the text file but I do not know how to control a specific line.
Here is my code:
Public Class Form1
Private Sub btnSubmit_Click(sender As System.Object, e As System.EventArgs) Handles btnSubmit.Click
Dim writer As New System.IO.StreamWriter("/text.txt", True)
writer.WriteLine(txtFirstName.Text)
writer.WriteLine(txtLastName.Text)
writer.WriteLine("-------------------------------------")
writer.Close()
End Sub
Private Sub btnRead_Click(sender As System.Object, e As System.EventArgs) Handles btnRead.Click
Dim reader As New System.IO.StreamReader("/text.txt")
Dim FirstName, LastName As String
FirstName = reader.ReadLine()
LastName = reader.ReadLine()
reader.Close()
txtFirstName.Text = FirstName
txtLastName.Text = LastName
End Sub
Private Sub btnClear_Click(sender As System.Object, e As System.EventArgs) Handles btnClear.Click
txtFirstName.Clear()
txtLastName.Clear()
End Sub
End Class
Any help would be appreciated. Thanks!
You will have to read all lines up to the one you're interested in. For example:
Function ReadLineWithNumberFrom(filePath As String, ByVal lineNumber As Integer) As String
Using file As New StreamReader(filePath)
' Skip all preceding lines: '
For i As Integer = 1 To lineNumber - 1
If file.ReadLine() Is Nothing Then
Throw New ArgumentOutOfRangeException("lineNumber")
End If
Next
' Attempt to read the line you're interested in: '
Dim line As String = file.ReadLine()
If line Is Nothing Then
Throw New ArgumentOutOfRangeException("lineNumber")
End If
' Succeded!
Return line
End Using
End Function
This is because lines of text are variable-length records, and there is no way to guess the exact file offset where a specific line begins — not without an index.
If you frequently need to load a specific line, you have some more options:
Load the complete text file into memory, e.g. by using File.ReadAllLines("Foobar.txt"). This returns a String() array which you can access by line number directly.
Create a line number index manually. That is, process a text file line by line, and fill a Dictionary(Of Integer, Integer) as you go. The keys are line numbers, and the values are file offsets. This allows you to .Seek right to the beginning of a specific line without having to keep the whole file in memory.
Try this:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim reader As New System.IO.StreamReader("C:\text.txt")
Dim allLines As List(Of String) = New List(Of String)
Do While Not reader.EndOfStream
allLines.Add(reader.ReadLine())
Loop
reader.Close()
txtFirstName.Text = ReadLine(5, allLines)
txtLastName.Text = ReadLine(6, allLines)
End Sub
Public Function ReadLine(lineNumber As Integer, lines As List(Of String)) As String
Return lines(lineNumber - 1)
End Function
If you had a file with this:
Line 1
Line 2
Line 3
Line 4
My Name
My LastName
your name textbox will have 'My Name' and your LastName textbox will have 'My LastName'.
This is very simple, try this:
Dim strLineText As String
Dim intLineNumber As Integer
LineNumber=3
myLine = File.ReadAllLines("D:\text.txt").ElementAt(LineNumber).ToString
Yet another option
Private Function readNthLine(fileAndPath As String, lineNumber As Integer) As String
Dim nthLine As String = Nothing
Dim n As Integer
Try
Using sr As StreamReader = New StreamReader(fileAndPath)
n = 0
Do While (sr.Peek() >= 0) And (n < lineNumber)
sr.ReadLine()
n += 1
Loop
If sr.Peek() >= 0 Then
nthLine = sr.ReadLine()
End If
End Using
Catch ex As Exception
Throw
End Try
Return nthLine
End Function
i tried this and it works fine. using VB Express
content inside test.txt:
line1
line2
1
John
then in the form i add
textbox1
textbox2
label1
label2
and a button.
code inside the button:
Private Sub Button2_Click_1(sender As Object, e As EventArgs) Handles Button2.Click
Dim myLine As String
Dim lineNumber0 As Integer
lineNumber0 = 0
Dim lineNumber1 As Integer
lineNumber1 = 1
Dim lineNumber2 As Integer
lineNumber2 = 2
Dim lineNumber3 As Integer
lineNumber3 = 3
TextBox1.Text=File.ReadAllLines("D:\test.txt").ElementAt(lineNumber0).ToString
TextBox2.Text=File.ReadAllLines("D:\test.txt").ElementAt(lineNumber1).ToString
Label1.Text = File.ReadAllLines("D:\test.txt").ElementAt(lineNumber2).ToString
Label2.Text = File.ReadAllLines("D:\test.txt").ElementAt(lineNumber3).ToString
End Sub
Here's a simple but effective solution:
Dim Reader As String = System.IO.File.ReadAllLines("C:\File.txt")(1)
MsgBox("Line 1: " + Reader)
The MsgBox should show the first line of C:\File.txt.