Read complex text file using Vb.net - vb.net

File Structure
RECORD
1234567890,123456789,1234567,Address1,,City,State,Zip,USA,Phone,,,,,,,,,
EmpName,DBAName,ID,,Address1,,Address1,City,60603,USA,234567890,,,,
C,03/13/2017,,1,2,
RECORD
1234567890,123456789,1234567,Address1,,City,State,Zip,USA,Phone,,,,,,,,,
EmpName2,DBAName2,ID2,,Address2,,Address2,City2,60603,USA,234567890,,,,
C,03/13/2017,,1,2,
Looking at the above file structure, I want to loop through file and for each record(RECORD), I want to put next three lines in one array and then next record in separate array.
I am looking for skeleton code, I am very new in programming using stream readers.
Code so far
Dim read As New System.IO.StreamReader("C:\New Text.txt")
Dim a As String
For Each a In read.ReadLine
If read.ReadLine.Equals("RECORD") Then
\\How do I read next 3 lines and put them in one array with comma delimiter
End If
Next

You need a data structure where you will keep the lines loaded and then start your loop
' Here you will keep the 3 lines block joined together and splitted on comma
Dim records = new List(Of String())()
Using read As New System.IO.StreamReader("C:\New Text.txt")
Dim a As String
' Read each line (Assuming that we start with a RECORD line
For Each a In read.ReadLine
' Do not read another line, but just test what is present in the string
If a.Equals("RECORD") Then
' Now read the 3 following lines....
Dim line1 = read.ReadLine
Dim line2 = read.ReadLine
Dim line3 = read.ReadLine
'Join the lines togeter
Dim record = string.Join("", line1, line2, line3).
' Split on the comma to produce an array of strings. The fields.
Dim fields = record.Split(","c)
records.Add(fields)
End If
Next
End Using
Of course this should be enhanced using a proper class that describe your inputs where each property of the class represent a field of the CSV file loaded. And then you could change the List(Of String()) to a List(Of YourClassData)
Keep in mind that this solution is extremely dependant of an exact file structure. A line with the "RECORD" content should be always followed by three lines of data. (No blank lines allowed between the three data lines)

Dim read As New System.IO.StreamReader("C:\New Text.txt")
//I usually only do C#, but rough VB.NEt code: I did not rcreate your array for you, figured you got that :-)
Dim a As String
Dim myConcatString as String
For Each a In read.ReadLine
Dim myReadLine as String
myReadLine = read.ReadLine
If myReadLine.Equals("RECORD") Then
myConcatString = myConcatString & myReadLine
\\How do I read next 3 lines and put them in one array with comma delimiter
else
//add myConcatString to array if not null....
myConcatString =""
End If
Next

Related

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

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

Saving contents of multiple text boxes and possibly combo boxes

I'm working on a basic application that lets you track experience earned across up to 3 skills. The names of the skills are in a combo box (not sure if the best) and the beginning and ending values are in text boxes.
I want to add a save button that saves the ending values and selected skills, when pressing the load button it would populate the combo boxes with saved skills and input the old ending values into the new beginning ones.
I've been working on this all day, searching for a long time I've come up with similar solutions but nothing seems to work right. I'm still a bit of a beginner so some of the solutions I don't understand. Also, this has to work for VBNet.
The closest solution I've come across is:
File.WriteAllText("C:\Data.txt", String.Join("|", new String({TextBox1.Text, TextBox2.Text, TextBox3.Text}))
I'd like the file to stay with the project in the main directory though. Would this work for combo boxes as well, and how to load the values back in?
I'm still a newbie to VB, hope this question makes sense.
If I get your idea right, please find some functions below if they can help:
One can read (or write) text:
This one can populate the needed string to 3 textboxes txtSkill1, txtSkill2, txtSkill3
Sub ReadTextFile()
Dim lineCount As Integer = 0
Dim rndInstance As New Random
Dim idx As Integer = 0
Dim selectedLine As String = ""
Dim txt As String = "Skills.txt"
If Not File.Exists(txt) Then
File.Create(txt).Dispose()
Dim objWriter As New System.IO.StreamWriter(txt, True)
' 2 sample text lines:
objWriter.WriteLine("Negotiating - Interpersonal - Working independently")
objWriter.WriteLine("Goal oriented - Leadership - Teamwork")
objWriter.Close()
End If
lineCount = File.ReadAllLines(txt).Length
idx = rndInstance.Next(1, lineCount + 1) ' the index can be random if you want, or run from (1 to lineCount)
selectedLine = ReadLineWithNumberFrom(txt, idx)
Dim pattern As String = "-" ' split on hyphens
Dim subStrings() As String = Regex.Split(selectedLine, pattern)
txtSkill1.Text = subStrings(0)
txtSkill2.Text = subStrings(1)
txtSkill3.Text = subStrings(2)
End Sub
One can read a string from a specific line number:
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
' Succeeded!
Return line
End Using
End Function
Now with the functions allow you to write to any text file, to read from any text file, from any line number, with specific separator (here is the hyphen -- char), you can Save and Load any string you need.

VB.net How to remove quotes characters from a streamReader.readline.split()

I had built a project that read data from a report and it used to work fine but now for some reason the report puts every thing in to strings. So I want to modify my stream reader to remove or ignore the quotes as it reads the lines.
This is a snipet of the part that reads the lines.
Dim RawEntList As New List(Of Array)()
Dim newline() As String
Dim CurrentAccountName As String
Dim CurrentAccount As Account
Dim AccountNameExsists As Boolean
Dim NewAccount As Account
Dim NewEntry As Entrey
Dim WrongFileErrorTrigger As String
ListOfLoadedAccountNames.Clear()
'opens the file
Try
Dim sr As New IO.StreamReader(File1Loc)
Console.WriteLine("Loading full report please waite")
MsgBox("Loading full report may take a while.")
'While we have not finished reading the file
While (Not sr.EndOfStream)
'spliting eatch line up into an array
newline = sr.ReadLine.Split(","c)
'storring eatch array into a list
RawEntList.Add(newline)
End While
And then of course I iterate through the list to pull out information to populate objects like this:
For Each Entr In RawEntList
CurrentAccountName = Entr(36)
AccountNameExsists = False
For Each AccountName In ListOfLoadedAccountNames
If CurrentAccountName = AccountName Then
AccountNameExsists = True
End If
Next
You could just do
StringName.Replace(ControlChars.Quote, "")
or
StringName.Replace(Chr(34), "")
OR
streamReader.readline.split().Replace(Chr(34), "")
How about doing the replace before the split, after the readline? That should save iteration multiplication, or better yet (if possible), do a replace on the entire file (if the data is formatted in the way it can be done & you have enough memory) using the ReadAllText method of the File object, do your replace, then read the lines from memory to build your array (super fast!).
File.ReadAllText(path)

How to read from a 2-line text file and output each line to 2 variables in vb.net

Hello in my program I need for a text file containing 2 lines to be read and each line's contents to be put into their own variable. the text file is called "account.txt" and is under the directory Documents. the code i have curently that sees if it exists is this:
If File.Exists(System.IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.MyDocuments, "Account.txt")) Then
MsgBox("Account found and is being loaded!")
End If
I would like in that if statement for the file to be read and each line to be read and contents to be put into their own variable. Any help is greatly appreciated!
You could either use a collection like String() or List(Of String) or read them with File.ReadLines or File.ReadAllLines and assign index 0 to variable 1 and index 1 to variable 2:
Dim path = Path.Combine(My.Computer.FileSystem.SpecialDirectories.MyDocuments, "Account.txt")
If File.Exists(path) Then
Dim allLines = File.ReadAllLines(path)
Dim line1 As String = allLines(0) ' indices are zero based
Dim line2 As String = allLines(1)
End If
You can also use ElementAtOrDefault(1) instead of allLines(1) if you're not sure if the file contains two lines at all. It'l be Nothing if it contains less:
Dim line2 As String = allLines.ElementAtOrDefault(1) ' can be Nothing
If File.Exists(System.IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.MyDocuments, "Account.txt")) Then
Dim accountReader As StreamReader = new StreamReader(My.Computer.FileSystem.SpecialDirectories.MyDocuments, "Account.txt")
Dim line1 As String = accountReader.ReadLine()
Dim line2 As String = accountReader.ReadLine()
reader.Close()
End If
This should work, have not tested it I usually work on C# so I tried to convert it to VB.Net I usually prefer to reader all lines into arrays and before assigned to it I do all necessary checks but this should get you started.
I seperated it like this since you mentioned that you want line contents into different variables.
Hope this helps you :)

Read text file with tab and carraige return format to store them in array

I have to text file in the following format :
Word[tab][tab]Word[Carriage Return]
Word[tab][tab]Word[Carriage Return]
Word[tab][tab]Word[Carriage Return]
I want to get all the words before the tab into one array or to create a new text file and the all the words after the tab into another array or create a new text file too.
Here my function to get the words before tab into an array :
Protected Sub MakeWordListBeforeTab()
Dim filename As String = "D:\lao\00001.txt"
'read from file'
Dim MyStream As New StreamReader(filename)
'words before tab
Dim WordBeforeTabArr() As String = MyStream.ReadToEnd.Split(CChar("\t"))
MyStream.Close()
'test to see the word in array
For d As Integer = 0 To WordBeforeTabArr.Length - 1
MsgBox(WordBeforeTabArr(d))
Next
End Sub
I wrote the above function to get all words before tab but I got all the words into array. I've been trying to use the Split method above. What is another method to split those words ? Can anyone show me some code to get this done right ?
I know this can be done with regular expression but I don't know regex yet. If you can show me how to get this done with regex it'll be awesome. Thanks.
You could try the split function on String. It could be used like this:
Dim lines() As String = IO.File.ReadAllLines(filename)
For Each line As String In lines
Dim words() As String = _
line.Split(New Char() {vbTab}, StringSplitOptions.RemoveEmptyEntries)
Next
The words array for each line would the two words. One word at each position. You could fill your two arrays or write the values out to a text file or file as you split the lines of the input file in the loop.
First of all above code is not compiling: See proper code as follows:
Dim lines() As String = IO.File.ReadAllLines(test_Filename)
For Each line As String In lines
Dim words() As String = _
line.Split("\t".ToCharArray()(0), StringSplitOptions.RemoveEmptyEntries)
Next