Read from text file, store data into corresponding structure every 6 element, and then form an array - vb.net

The text file contains the following: inside the [], anything inside () was not in the text file, just for clarification
[1(ID)
Jimmy(First name)
Paul (Last name)
78 (marks1)
80 (marks2)
92 (marks3)
2
Ben
James
67
82
73
]
I created a structure that holds student details including their name, id, marks in each subject.
Private Structure StudInfo
Public FName As String
Public LName As String
Public StudentId As Integer
Public ScMark As Integer
Public EnMark As Integer
Public MaMark As Integer
The program needs to read the first six elements in a row, storing each element into the corresponding structure type, then let it become the first element of an array"students()", and then next six elements, let it become the second element of that array. I have no idea how to use loops to do that.
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
'create an array that hold student details
Dim Students() As StudInfo
' read from text file
Dim FileNum As Integer = FreeFile()
Dim TempS As String = ""
Dim TempL As String
FileOpen(FileNum, "some.text", OpenMode.Input)
Do Until EOF(FileNum)
TempL = LineInput(FileNum)
TempS = TempL + vbCrLf
Loop
End Sub
Thank you.

You have to use a BinaryReader (which takes a IO.Stream as it's constructor), then you can read the data type you want, into the variable you want.
The problem you will have is the data will not be searchable (ie. you cannot read the 30th record, unless you physically read the first 29, because the strings are of variable length, and therefore the record is variable length), this also applies to modifying a record (you cant make it bigger, because it will overwrite the next record).
The answer is to work with fixed length records, or field offsets or fixed length strings. Then you will have a records of predictable size, and you can determine the amount of records by dividing the file length by the record size.
Hope this helps.

You could try something like this:
Public Class Form1
Private Students As New List(Of StudInfo)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Students.Clear()
Dim fileName = "c:\some folder\directory\someFile.txt"
Using sr As New System.IO.StreamReader(fileName)
Dim value As Integer
Dim strValue As String
While Not sr.EndOfStream
Try
Dim student As New StudInfo
strValue = sr.ReadLine().Trim("[]")
If Integer.TryParse(strValue, value) Then
student.StudentId = value
Else
MessageBox.Show("Error Converting StudentID to Integer")
Exit Sub
End If
student.FName = sr.ReadLine().Trim("[]")
student.LName = sr.ReadLine().Trim("[]")
strValue = sr.ReadLine().Trim("[]")
If Integer.TryParse(strValue, value) Then
student.ScMark = value
Else
MessageBox.Show("Error Converting ScMark to Integer")
Exit Sub
End If
strValue = sr.ReadLine().Trim("[]")
If Integer.TryParse(strValue, value) Then
student.EnMark = value
Else
MessageBox.Show("Error Converting EnMark to Integer")
Exit Sub
End If
strValue = sr.ReadLine().Trim("[]")
If Integer.TryParse(strValue, value) Then
student.MaMark = value
Else
MessageBox.Show("Error Converting MaMark to Integer")
Exit Sub
End If
Students.Add(student)
Catch ex As Exception
MessageBox.Show("Error reading file. All records may not have been created.")
End Try
End While
MessageBox.Show("Done!")
End Using
End Sub
Private Class StudInfo
Public FName As String
Public LName As String
Public StudentId As Integer
Public ScMark As Integer
Public EnMark As Integer
Public MaMark As Integer
End Class
End Class

It depends a bit on the exact format of your text file.
If the file only contains the data for the two students (no brackets or blank lines), then all you need to do is to open the file and read 6 lines, add the data to your structure. and read the next 6 lines. If you have an undetermined number of students in the text file, then you would be better using a List. Other wise you're goiing to have to use extra processing time to Redim the array each time you want to add a student and keep track of the array size an all sorts of messing around.
However. Lets go with the most straightforward answer and assume your data has no brackets or blank lines and that there are only two students.
This code should work just fine. If you have a different definite number of students, then you will need to change the size of the Students array.
I'm also assuming that the data is correctly formatted and there are no non-numeric characters are in the lines where there shouldn't be.
Private Sub ReadStudentInfo()
'create an array that hold student details
Dim Students(2) As StudInfo
Dim index As Integer = 0
' read from text file
Dim datafile As New StreamReader("some.text")
Do Until datafile.EndOfStream
Dim tempStudent As StudInfo
With tempStudent
Integer.TryParse(datafile.ReadLine, .StudentId)
.FName = datafile.ReadLine
.LName = datafile.ReadLine
Integer.TryParse(datafile.ReadLine, .ScMark)
Integer.TryParse(datafile.ReadLine, .EnMark)
Integer.TryParse(datafile.ReadLine, .MaMark)
End With
Students(index) = tempStudent
index = index + 1
Loop
End Sub
If your text file does contain blank lines, just insert
datafile.ReadLine()
between each line of data - like this
Integer.TryParse(datafile.ReadLine, .ScMark)
datafile.ReadLine()
Integer.TryParse(datafile.ReadLine, .EnMark)
If you have the brackets in your text file, then you'll need to add extra code to remove them.

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

How to assign values from a file to variable

I have a text file and I wish to make code that puts the numbers into an array.
The program is required to read the data for each member from the text file. The program then uses this data to find then display the biggest value. The names of every member who has a value more than 70% of the largest is to be written on an empty text file so that the file can be printed out later.
Nikolai,Bryant,145.6
Susan,Brown,34.2
Teressa,Jones,398.5
Martin,Daly,256.9
Ross,Durrant,409.0
Greg,Watson,99.2
Wendy,Russell,87.4
Pamela,Adkins,73.6
Ian,Hunter,385.7
James,Kerr,505.2
Lesley,Wallace,68.4
Kim,Pettigrew,256.4
Steven,Johnstone,23.4
Ali,Hussain,12.1
Hasan,Abbas,302.0
Jacek,Nowak,199.9
Mirka,Kowalski,176.8
Rudo,Hyper,120.2
Tisa,Sullivan,484.2
Albert,Nvodo,385.8
So far all I have is this:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim FILE_NAME As String = "H:\S5\Computing\Programming\members.txt"
Dim objReader As New System.IO.StreamReader(FILE_NAME)
End Sub
End Class
You will need to add Imports System.IO at the top of you code file. This has a File class which contains the .ReadAllLines method. This method will return an array of all the lines in the text file.
'String.Split' will return an array of of the fields in the line which were delimited (separated) by a comma. The small c after "," tells the compiler that this is Char which what the .Split method expects.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim FILE_NAME As String = "H:\S5\Computing\Programming\members.txt"
Dim lines = File.ReadAllLines(FILE_NAME)
'Declare an array to hold your numbers VB arrays are declared arr(UBound)
'UBound is upper bound referring to highest index
'The highest index would be 1 less the lenght because indexes start at 0
Dim numbers(lines.Length - 1) As Single
Dim index As Integer 'Will be the index for the numbers array
'From the lines array we can loop through each line
For Each s As String In lines
Dim fields = s.Split(","c)
'Your fields array will have 3 elements, a first name at position (index) 0, last name at 1 and number at 2
'You only want the number - but it is not a number yet, it is still a string
'So we do a CSng to change it to a Single
numbers(index) = CSng(fields(2))
index += 1 'shortcut way to write index = index + 1
Next
For Each n As Single In numbers
Debug.Print(n.ToString)
Next
End Sub
The .TexFieldParser suggested by #jmcilhinney in comments has some extra features which would come in handy but this should get you started.

VB Parse a text file, match column 1 to a variable, pass column 2 to another variable

I've written a script that will take a table out of a program, and export it to the local drive in a comma delimited text file. What I need is a script to read the text file. The user will input a string in a text box from Public Class Form 1, then the string gets passed to another Sub in Public Class SpaceMenuClass. The handoff looks ok, but I can't figure out how to parse the text file (match column 1 with the string, and store column 2 from that line to pass back to the SpacemenuClass). I know this may seem ambiguous, but hopefully makes some sense. Thanks to anyone in advance.
From Form1 Class
Private Sub BtnPlano_Click_(sender As Object, e As EventArgs) Handles BtnPlano.Click
If TxtBoxPlano.Text <> "" Then
SpaceCommands.SearchPlano(TxtBoxPlano.Text)
Else MessageBox.Show("Please Enter a Valid Planogram Name!")
End If
TxtBoxPlano.Clear()
End Sub
From SpaceMenuClass:
Public Sub SearchPlano(PlanoName As String)
For Each Plano As Space.Planogram In SpacePlanning.ForPlanograms()
SpacePlanning.SetActivePlanogram(Plano.Number - 1)
'Go open the Searchplano table on the shared drive
SpacePlanning.OpenTableChartView(AnalysisFileName:="\\SERVER1\JDA\Tables\SearchPlano.pst")
'Export the table to a Tab Delimited Text file
SpacePlanning.ExportTableData(ExportFileName:="C:\Temp\JDA\SearchPlano.txt", ExportMethod:=ExportMethod.CommaSeparated, UseCurrency:=False, UseQuotedStrings:=False, UseThousandsSeparator:=False)
'Close the Table
SpacePlanning.CloseTableChartView(AnalysisFileName:="\\SERVER1\JDA\Tables\SearchPlano.pst")
' Open the text file and parse it
Dim str As System.IO.StreamReader = New System.IO.StreamReader(New System.IO.FileStream("C:\Temp\JDA\SearchPlano.txt", System.IO.FileMode.Open))
Dim strline, arr(), Name, Nbr As String
Try
NextLine:
strline = str.ReadLine
arr = strline.Split(",")
Name = arr(0)
Nbr = arr(1)
If Name = PlanoName Then
SpacePlanning.SetActivePlanogram(Plano.Number = Nbr)
GoTo Finish
Else
GoTo NextLine
End If
Catch
End Try
Next
Finish:
My.Computer.FileSystem.DeleteFile("C:\Temp\JDA\SearchPlano.Txt")
End Sub
You open the file for reading, then try to delete it before closing it. This would raise an exception. To avoid this, wrap the StreamReader in a Using block. The End Using automatically disposes of the object (closes the file for you).
Public Sub SearchPlano(planoName As String)
For Each plano As Space.Planogram In SpacePlanning.ForPlanograms()
SpacePlanning.SetActivePlanogram(plano.Number - 1)
'Go open the Searchplano table on the shared drive
SpacePlanning.OpenTableChartView(AnalysisFileName:="\\SERVER1\JDA\Tables\SearchPlano.pst")
'Export the table to a Tab Delimited Text file
SpacePlanning.ExportTableData(
ExportFileName:="C:\Temp\JDA\SearchPlano.txt", ExportMethod:=ExportMethod.CommaSeparated,
UseCurrency:=False, UseQuotedStrings:=False, UseThousandsSeparator:=False)
'Close the Table
SpacePlanning.CloseTableChartView(AnalysisFileName:="\\SERVER1\JDA\Tables\SearchPlano.pst")
' Open the text file and parse it
Using str = New System.IO.StreamReader("C:\Temp\JDA\SearchPlano.txt")
Dim arr(), name, nbr As String
Do
If str.EndOfStream Then
' didn't find item!!!
End If
arr = str.ReadLine.Split(",")
name = arr(0)
nbr = arr(1)
Loop Until name = planoName
SpacePlanning.SetActivePlanogram(plano.Number = nbr)
End Using
Next
My.Computer.FileSystem.DeleteFile("C:\Temp\JDA\SearchPlano.Txt")
End Sub
I also cleaned up your loop and added a check for EndOfStream, in case you couldn't find a match (this would have thrown an exception too).
Also, changed the StreamReader to just open the file. You had a nested FileStream object in there, which would have required another Using block, and is unnecessary.

VB 2010 array/write array to file

I'm close to getting this to work, but currently can't get any output to display in the listbox. I had it working, but needed to move some things around to get the join function to work.
In my program, a user enters input into a textbox and an array is displayed in a listbox based on what they type in. For example, if they type in "a", all foods (in the textfile that is connected to the program) that start with "a" will be displayed.
When there is output, I need to find a way to name this array (which is created based on what the user inputs) and join all of the items in the listbox (example: foods stacked on top of each other in the listbox will be shown at the bottom as a string).
I am posting the code that I have thus far; all of the errors that I'm getting (and potentially my logic errors) are just in the first public class until the end of the first if-next statement:
Public Class frmFoods
Dim foods() As String = IO.File.ReadAllLines("foods.txt")
Private Sub btnDisplay_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisplay.Click
Dim Letter As String = txtLetter.Text.ToUpper
Dim smallerarray() As Array
Dim userarray As String
lstOutput.Items.Clear()
If IsNumeric(txtLetter.Text) = False Then
For Each food As String In foods
smallerarray = listfoods(Letter)
lstOutput.Items.Add(Letter)
userarray = Join(smallerarray, ", ")
lstOutput.Items.Add(userarray)
Next
ElseIf IsNumeric(txtLetter.Text) = True Then
MessageBox.Show("Please enter a letter.")
Else
MessageBox.Show("The text box is empty")
End If
End Sub
Function listfoods(ByVal letter As String) As String()
Dim foodarray(foods.Count - 1) As String
Dim counter As Integer = 0
For Each food As String In foods
If food.StartsWith(letter) Then
foodarray(counter) = food
counter += 1
End If
Next
ReDim Preserve foodarray(counter - 1)
Return foodarray
End Function
you need to save the results of the listfoods function in a dictionary or similar and associate it with a key if you want to 'Name' it, although its not clear why you need to do this
As for listing the foods starting with the particular letter, you just need to iterate your result of the function listfoods and separate each one by a comma don't you?
What you have now will create many lists of each food as you are getting the list of food beginning with a particular letter for each food.. As I understand the question you only need to do that once.
Example:
Private Sub btnDisplay_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisplay.Click
Dim Letter As String = txtLetter.Text.ToUpper
Dim smallerarray() As Array
Dim userarray As String
lstOutput.Items.Clear()
If IsNumeric(txtLetter.Text) = False Then
'get all items from the file which begin with the letter the user chose
smallerarray = listfoods(Letter)
'add that letter to the output listbox
lstOutput.Items.Add(Letter)
'join all of the elements which begin with that letter
'into a single comma separated string
userarray = Join(smallerarray, ", ")
'add that string to the output
lstOutput.Items.Add(userarray)
ElseIf IsNumeric(txtLetter.Text) = True Then
MessageBox.Show("Please enter a letter.")
Else
MessageBox.Show("The text box is empty")
End If
End Sub
it would probably be useful for you to step through the code and see the values of the variable at each place and compare this with what you expect to see if you can see where the actual value differs from what your logically expect so you can start to identify where the issue is

Error In VB.Net code

I am getting the error "Format Exception was unhandled at "Do While objectReader.Peek <> -1
" and after. any help would be wonderful.
'Date: Class 03/20/2010
'Program Purpose: When code is executed data will be pulled from a text file
'that contains the named storms to find the average number of storms during the time
'period chosen by the user and to find the most active year. between the range of
'years 1990 and 2008
Option Strict On
Public Class frmHurricane
Private _intNumberOfHuricanes As Integer = 5
Public Shared _intSizeOfArray As Integer = 7
Public Shared _strHuricaneList(_intSizeOfArray) As String
Private _strID(_intSizeOfArray) As String
Private _decYears(_intSizeOfArray) As Decimal
Private _decFinal(_intSizeOfArray) As Decimal
Private _intNumber(_intSizeOfArray) As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'The frmHurricane load event reads the Hurricane text file and
'fill the combotBox object with the data.
'Initialize an instance of the StreamReader Object and declare variable page 675 on the book
Dim objectReader As IO.StreamReader
Dim strLocationAndNameOfFile As String = "C:\huricanes.txt"
Dim intCount As Integer = 0
Dim intFill As Integer
Dim strFileError As String = "The file is not available. Please restart application when available"
'This is where we code the file if it exist.
If IO.File.Exists(strLocationAndNameOfFile) Then
objectReader = IO.File.OpenText(strLocationAndNameOfFile)
'Read the file line by line until the file is complete
Do While objectReader.Peek <> -1
**_strHuricaneList(intCount) = objectReader.ReadLine()
_strID(intCount) = objectReader.ReadLine()
_decYears(intCount) = Convert.ToDecimal(objectReader.ReadLine())
_intNumber(intCount) = Convert.ToInt32(objectReader.ReadLine())
intCount += 1**
Loop
objectReader.Close()
'With any luck the data will go to the Data Box
For intFill = 0 To (_strID.Length - 1)
Me.cboByYear.Items.Add(_strID(intFill))
Next
Else
MsgBox(strFileError, , "Error")
Me.Close()
End If
End Sub
Put a break-point on these lines and step through your code:
_decYears(intCount) = Convert.ToDecimal(objectReader.ReadLine())
_intNumber(intCount) = Convert.ToInt32(objectReader.ReadLine())
Whatever is being returned by ReadLine isn't in the proper decimal or integer format when passed to the converters. You'll need to add some try/catch blocks around the do-while loop operations to handle it gracefully and make sure your data is formatted the way you expected since the wrong parts are being used in this scenario.
Also, each call to ReadLine is returning an entirely new line and the Peek check won't account for those. As long as you can trust your data that's fine.
Instead of using Convert.ToDecimal an Convert.ToInt32, try using Decimal.TryParse() and Int32.TryParse(). If they don't parse, you know your file isn't setup correctly. If they do parse, then you've loaded the value into a variable for your use.
EDIT:
Use it like this.
Dim myDecimal As Decimal
If Decimal.TryParse(objectReader.ReadLine(), myDecimal) Then
'your string successfully parsed. Use myDecimal however you want. It has the parsed value.
Else
'your string is not a decimal. Now that you know that, you can handle this situation here without having to catch an exception.
End If