StreamReader Only Reads and Outputs Last Line From MultiLine, Spaced Text File - vb.net

I'm trying to read values from a text file and input them into an array from where I can assign them to text boxes. My text file has the first line as a title name (string/char) and all subsequent lines contain numbers:
There are multiple lines and each value is split by a white-space. My current code is:
If openFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
Dim openreader As System.IO.StreamReader = New System.IO.StreamReader(openFileDialog1.FileName)
Try
While Not openreader.EndOfStream
Dim currentline As String
currentline = openreader.ReadLine()
currentline = currentline.Trim(" "c)
Dim inputparts() As String = currentline.Split(" "c)
TextBox1.Text = inputparts(0)
TextBox2.Text = inputparts(1) 'This gives out of bounds error
TextBox3.Text = inputparts(2) 'This gives out of bounds error
TextBox4.Text = inputparts(3) 'This gives out of bounds error
End While
Catch Ex As Exception
MessageBox.Show("The file could not be read. The original error is: " & Ex.Message)
End Try
openreader.Close()
End If
The issue with this is that the array inputparts has an out of bounds error for anything higher than inputparts(0) and inputparts(0), which is the only element recorded, is always the very last number of the last line. I did not want to define the dimensions of inputparts() since I was my input file to have the freedom to have a range of different values.
Why is the array not recording any values other than the final one - is it because my currentline ends up being the last line - and how can I fix this? Any help would be appreciated!

One way to put the parts which come from the split into textboxes would be to have references to the textboxes in an array and set them from the array of items from the line.
With Math.Min we can be sure that if there are not enough items on the line then we don't try to set the text to something which doesn't exist.
Using openreader As StreamReader = New StreamReader(openFileDialog1.FileName)
Dim tb = {TextBox1, TextBox2, TextBox3, TextBox4}
Try
While Not openreader.EndOfStream
Dim currentline As String
currentline = openreader.ReadLine()
currentline = currentline.Trim(" "c)
Dim inputparts() As String = currentline.Split(" "c)
For i = 0 To Math.Min(tb.Length, inputparts.Length)
tb(i).Text = inputparts(i)
Next
End While
Catch ex As Exception
MessageBox.Show("The file could not be read. The original error is: " & ex.Message)
End Try
End Using
I used the Using statement because it makes sure that the file is closed even if an exception occurs.
If you add Imports System.IO at the very top of the code, you don't have to keep typing it in things like System.IO.StreamReader.

Related

Parse Log File - Reading from the end first

Having some trouble with a log file I need to parse and display certain fields in a data grid view. The log file is a large tab delimited file and I can read it and parse the array easily. The issue is that I want to start at the END of the file and read backwards until I hit a certain value in one of the fields. Then I want to start reading forward again until it hits the end of the file. While it's reading to the end I want it to fill the data grid view with certain fields. Here's what I have so far -
Looking at the code - it needs to read from the end until the 4th field equals zero and then start reading forward again. I can also read from the end, saving the values to the data grid view as I go until I hit that 0 if that's easier.
Thanks for the help!
The other option would be to read the file and save it in reverse, line by line - the last line first, the 2nd to last line 2nd, etc. That would be really nice as I have another function that will need to read the file and it also needs to go from the end to the beginning.
Private Sub btnParseLog_Click(sender As Object, e As EventArgs) Handles btnParseLog.Click
Dim FileLocation As String = "BLAHBLAHBLAH"
Dim LogFile As String = "LOGFILE"
DataGridView1.ColumnCount = 3
DataGridView1.ColumnHeadersVisible = True
' Set the column header style.
Dim columnHeaderStyle As New DataGridViewCellStyle()
columnHeaderStyle.BackColor = Color.Beige
columnHeaderStyle.Font = New Font("Verdana", 10, FontStyle.Bold)
DataGridView1.ColumnHeadersDefaultCellStyle = columnHeaderStyle
DataGridView1.Columns(0).Name = "User"
DataGridView1.Columns(1).Name = "Number"
DataGridView1.Columns(2).Name = "Time"
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(LogFile)
MyReader.TextFieldType =
Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {vbTab}
Dim TotalLineCount As Integer = File.ReadAllLines(LogFile).Length
Dim currentRow As String()
Dim RowCount As Integer = 0
'Loop through all of the fields in the file.
'If any lines are corrupt, report an error and continue parsing.
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
RowCount = RowCount + 1
' Include code here to handle the row.
If RowCount = TotalLineCount Then
While Not currentRow(4).ToString = 0
DataGridView1.Rows.Add(currentRow(1).ToString, currentRow(4).ToString, currentRow(7).ToString)
RowCount = RowCount - 1
End While
End If
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
" is invalid. Skipping")
End Try
End While
End Using
End Sub

VB "Index was out of range, must be non-negative and less than the size of the collection." When trying to generate a random number more than once

So I'm trying to generate a random number on button click. Now this number needs to be between two numbers that are inside my text file with various other things all separated by the "|" symbol. The number is then put into the text of a textbox which is being created after i run the form. I can get everything to work perfectly once, but as soon as i try to generate a different random number it gives me the error: "Index was out of range, must be non-negative and less than the size of the collection." Here is the main code as well as the block that generates the textbox after loading the form. As well as the contents of my text file.
Private Sub generate()
Dim newrandom As New Random
Try
Using sr As New StreamReader(itemfile) 'Create a stream reader object for the file
'While we have lines to read in
Do Until sr.EndOfStream
Dim line As String
line = sr.ReadLine() 'Read a line out one at a time
Dim tmp()
tmp = Split(line, "|")
rows(lineNum).buybutton.Text = tmp(1)
rows(lineNum).buyprice.Text = newrandom.Next(tmp(2), tmp(3)) 'Generate the random number between two values
rows(lineNum).amount.Text = tmp(4)
rows(lineNum).sellprice.Text = tmp(5)
rows(lineNum).sellbutton.Text = tmp(1)
lineNum += 1
If sr.EndOfStream = True Then
sr.Close()
End If
Loop
End Using
Catch x As Exception ' Report any errors in reading the line of code
Dim errMsg As String = "Problems: " & x.Message
MsgBox(errMsg)
End Try
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
rows = New List(Of duplicate)
For dupnum = 0 To 11
'There are about 5 more of these above this one but they all have set values, this is the only troublesome one
Dim buyprice As System.Windows.Forms.TextBox
buyprice = New System.Windows.Forms.TextBox
buyprice.Width = textbox1.Width
buyprice.Height = textbox1.Height
buyprice.Left = textbox1.Left
buyprice.Top = textbox1.Top + 30 * dupnum
buyprice.Name = "buypricetxt" + Str(dupnum)
Me.Controls.Add(buyprice)
pair = New itemrow
pair.sellbutton = sellbutton
pair.amount = amounttxt
pair.sellprice = sellpricetxt
pair.buybutton = buybutton
pair.buyprice = buypricetxt
rows.Add(pair)
next
end sub
'textfile contents
0|Iron Sword|10|30|0|0
1|Steel Sword|20|40|0|0
2|Iron Shield|15|35|0|0
3|Steel Shield|30|50|0|0
4|Bread|5|10|0|0
5|Cloak|15|30|0|0
6|Tent|40|80|0|0
7|Leather Armour|50|70|0|0
8|Horse|100|200|0|0
9|Saddle|50|75|0|0
10|Opium|200|500|0|0
11|House|1000|5000|0|0
Not sure what else to add, if you know whats wrong please help :/ thanks
Add the following two lines to the start of generate():
Private Sub generate()
Dim lineNum
lineNum = 0
This ensures that you don't point to a value of lineNum outside of the collection.
I usually consider it a good idea to add
Option Explicit
to my code - it forces me to declare my variables, and then I think about their initialization more carefully. It helps me consider their scope, too.
Try this little modification.
I took your original Sub and changed a little bit take a try and let us know if it solve the issue
Private Sub generate()
Dim line As String
Dim lineNum As Integer = 0
Dim rn As New Random(Now.Millisecond)
Try
Using sr As New StreamReader(_path) 'Create a stream reader object for the file
'While we have lines to read in
While sr.Peek > 0
line = sr.ReadLine() 'Read a line out one at a time
If Not String.IsNullOrEmpty(line) And Not String.IsNullOrWhiteSpace(line) Then
Dim tmp()
tmp = Split(line, "|")
rows(lineNum).buybutton.Text = tmp(1)
rows(lineNum).buyprice.Text = rn.Next(CInt(tmp(2)), CInt(tmp(3))) 'Generate the random number between two values
rows(lineNum).amount.Text = tmp(4)
rows(lineNum).sellprice.Text = tmp(5)
rows(lineNum).sellbutton.Text = tmp(1)
lineNum += 1
End If
End While
End Using
Catch x As Exception ' Report any errors in reading the line of code
Dim errMsg As String = "Problems: " & x.Message
MsgBox(errMsg)
End Try
End Sub

I need to delete something from a .txt file but it leaves an empty line! I have set code to stop this but it deletes something else

I need to set this piece of code in vb so that a user can delete a specific string from a .txt document. But when they do, it leaves an empty line. I then got more code to stop this but then it deletes something else within the file with the empty line.
Code:
If (txtDelUser.Text = "admin" Or txtDelUser.Text = "guest") Then
rtbOutput2.Text = "You tried to delete: " + txtDelUser.Text + ". But the user is protected by default."
Else
Dim ln As Integer = 1
rtbOutput.Text.First(Of Text = Text.CopyTo.ClipBoard
'Removes the selected username from list of usernames
Dim lines As New List(Of String)
Using sr As New StreamReader("C:\ProgramData\Hax Client\User Data\All Usernames.txt")
While Not sr.EndOfStream
lines.Add(sr.ReadLine)
End While
End Using
For Each line As String In lines
If line.Contains(txtDelUser.Text) Then
lines.Remove(line)
Exit For 'must exit as we changed the iteration
End If
Next
'End of removing the line
Dim fs As New FileStream("C:\ProgramData\Hax Client\User Data\All Usernames.txt", FileMode.Append)
Dim sw As New StreamWriter(fs)
Dim foundBlank As Boolean
For Each line As String In lines
If line.Length > 0 Then
sw.WriteLine(line)
' Reset blank line flag
foundBlank = False
Else
If Not foundBlank Then
' Blank line: write first one
sw.WriteLine(line)
' Set flag to indicate that blank line was found
foundBlank = True
End If
End If
Next
sw.Close()
fs.Close()
My.Computer.FileSystem.FileExists("C:\ProgramData\Hax Client\User Data\" + txtDelUser.Text)
My.Computer.FileSystem.DeleteFile("C:\ProgramData\Hax Client\User Data\" + txtDelUser.Text + ".txt")
rtbOutput2.Text = "Deleted user: " + txtDelUser.Text
End If
Text file:
admin
guest
testing
Can you either look over my code or give me some code that will allow me to delete from the .txt file, by whats entered into a textbox, without leaving an empty or a way to get rid of the empty line.
Thanks!
You can store the items that you want to write back to file in another list, linesToKeep, like this:
Dim linesToKeep As New List(Of String)
For Each line As String In lines
If Not line.Contains(txtDelUser.Text) Then
linesToKeep.Add(line)
End If
Next
' Write all lines in linesToKeep back to file
For Each line As String In lines
sw.WriteLine(line)
Next
UPDATE:
Here is what the full code should look like using this solution applied to the code posted:
If (txtDelUser.Text = "admin" Or txtDelUser.Text = "guest") Then
rtbOutput2.Text = "You tried to delete: " + txtDelUser.Text + ". But the user is protected by default."
Else
Dim ln As Integer = 1
rtbOutput.Text.First(Of Text = Text.CopyTo.ClipBoard
'Removes the selected username from list of usernames
Dim lines As New List(Of String)
Using sr As New StreamReader("C:\ProgramData\Hax Client\User Data\All Usernames.txt")
While Not sr.EndOfStream
lines.Add(sr.ReadLine)
End While
End Using
' Instead of removing items from the list we read from file
' we are going to keep track of what we want to keep and write back to file later
Dim linesToKeep As New List(Of String)
For Each line As String In lines
If Not line.Contains(txtDelUser.Text) Then
linesToKeep.Add(line)
End If
Next
Dim fs As New FileStream("C:\ProgramData\Hax Client\User Data\All Usernames.txt", FileMode.Append)
Dim sw As New StreamWriter(fs)
' Write all lines in linesToKeep back to file
For Each line As String In lines
sw.WriteLine(line)
Next
sw.Close()
fs.Close()
My.Computer.FileSystem.FileExists("C:\ProgramData\Hax Client\User Data\" + txtDelUser.Text)
My.Computer.FileSystem.DeleteFile("C:\ProgramData\Hax Client\User Data\" + txtDelUser.Text + ".txt")
rtbOutput2.Text = "Deleted user: " + txtDelUser.Text
End If

How to check if lines in string are separated by space?

I'm building a program that gets the publisher of the book by scanning its title page and using OCR … since publishers are always at the bottom of the title page I'm thinking that a detecting lines that are separated by space is a solution but I don't know how to test for that. Here is my code:
Dim builder As New StringBuilder()
Dim reader As New StringReader(txtOCR.Text)
Dim iCounter As Integer = 0
While True
Dim line As String = reader.ReadLine()
If line Is Nothing Then Exit While
'i want to put the condition here
End While
txtPublisher.Text = builder.ToString()
Do you mean empty lines? Then you can do this:
Dim bEmpty As Boolean
And then inside the loop:
If line.Trim().Length = 0 Then
bEmpty = True
Else
If bEmpty Then
'...
End If
bEmpty = False
End If
Why not do the following: from the bottom, go up until you find the first non-empty line (no idea how the OCR works … maybe the bottom-most line is always non-empty, in which case this is redundant). In the next step, go up until the first empty line. The text in the middle is the publisher.
You don’t need the StringReader for that:
Dim lines As String() = txtOCR.Text.Split(Environment.NewLine)
Dim bottom As Integer = lines.Length - 1
' Find bottom-most non-empty line.
Do While String.IsNullOrWhitespace(lines(bottom))
bottom -= 1
Loop
' Find empty line above that
Dim top As Integer = bottom - 1
Do Until String.IsNullOrWhitespace(lines(top))
top -= 1
Loop
Dim publisherSubset As New String(bottom - top)()
Array.Copy(lines, top + 1, publisherSubset, 0, bottom - top)
Dim publisher As String = String.Join(Environment.NewLine, publisherSubset)
But to be honest I don’t think this is a particularly good approach. It’s inflexible and doesn’t cope well with unexpected formatting. I’d instead use a regular expression to describe what the publisher string (and its context) looks like. And maybe even that isn’t enough and you have to put some thought into describing the whole page to extrapolate which of the bits is the publisher.
Assuming the publisher is always on the last line and always comes after an empty line. Then perhaps the following?
Dim Lines as New List(Of String)
Dim currentLine as String = ""
Dim previousLine as String = ""
Using reader As StreamReader = New StreamReader(txtOCR.Txt)
currentLine = reader.ReadLine
If String.IsNullOrWhiteSpace(previousLine) then lines.Add(currentLine)
previousLine = currentLine
End Using
txtPublisher.Text = lines.LastOrDefault()
To ignore if the previous line is blank/empty:
Dim Lines as New List(Of String)
Using reader As StreamReader = New StreamReader(txtOCR.Txt)
lines.Add(reader.ReadLine)
End Using
txtPublisher.Text = lines.LastOrDefault()

Find a specific line of text in a text document and insert the next 37 lines of text into a database

Helo,
I have an SQL database, and 50 text files, and Visual Basic 2010 Premimum,
I need to find a specific line of text in the text files and then take the next 37 lines of text and save them in my database. I need advice as to point me in the right direction. Also if anyone might know of a book I can use for future reference it would be greatly appreciated.
Const textToFind As String = "a specific line of text"
Const maxLineCount As Int32 = 37
Dim allLines As New List(Of String)
Dim path As String = "c:\temp\MyTest.txt"
Try
If File.Exists(path) Then
File.Delete(path)
End If
Dim sw As StreamWriter = New StreamWriter(path)
For i As Int32 = 1 To 100
sw.WriteLine("This")
sw.WriteLine("is some text")
sw.WriteLine("to test")
sw.WriteLine("Reading")
sw.WriteLine("a specific line of text")
Next
sw.Close()
Dim sr As StreamReader = New StreamReader(path)
Dim lineCounter As Int32 = 0
Dim lineFound As Int32 = -1
Do While sr.Peek() >= 0
Dim line As String = sr.ReadLine
If lineFound = -1 Then
If line.Equals(textToFind) Then
lineFound = 0
End If
Else
lineCounter += 1
If lineCounter <= maxLineCount Then
allLines.Add(line)
Else
Exit Do
End If
End If
Loop
sr.Close()
' save found lines to the database '
Catch ex As Exception
Console.WriteLine("The process failed: {0}", ex.ToString())
End Try
As for parsing the file, it's easy to search files line-by-line:
Var i = 0
Var foundOnLineNumber = -1
For Each line In File.ReadAllLines("<file name here>")
i = i + 1
If foundOnLineNumber > 0 Then
' Add line to database
Else If <criteria for finding "that" line> Then
foundOnLineNumber = i
End If
Next
I've never been good at VB (I usually do C#, so this might not compile). Try to figure out what criteria you are looking for and replace that in the code above. Here is a list of VB.NET books. Find one that covers ADO or some other database access technology. I think your biggest help will be to simply get a good grasp on the VB language and the facilities that .NET has at its disposal.