Visual Basic Append to a specific point in a text file - vb.net

I am currently trying to manipulate a line in a file that we are using to retain data, using comma delimiters. For example -
121,1212, XJAY,Sean K,Kean S,AAAA-BBBB-AAAA-BBBB-AAAA
12456,987654,WYST,Steve Jobs,Bill Gates,CAAA-BBBB-AAAA-BBBB-AAAA
If I assume that the last line is always a unique code, is it possible to identify that line in the text file and append it with another field?
Prior research has been reading through the APIs for StreamReader and StreamWriter, and looking through other StackOverflow questions, however most questions seem focused on just appending to the end of the file, or in different languages!
As always thank you for your time, and if there is anything I've left off please let me know!

You can't manipulate a line in a file in any reasonably easy way.
There are no methods to work with lines in a file, because files are not line based. They are not even character based. The bytes in the file are decoded into characters, then the line break characters are recognised and the characters can be split into lines.
The easiest way to manipulate a line is to read the entire file into a string array, change the string that you want change, then write the entire string array to the file.
Example:
Dim fileName As String = "c:\data.txt"
Dim lines As String() = File.ReadAllLines(fileName)
For i As Integer = 0 To lines.Length - 1
Dim line As String = lines(i)
If line.StartsWith("12456,") Then
lines(i) = line & ",More data"
End If
Next
File.WriteAllLines(fileName, lines)

If you are looking for a way to parse Each line with StreamReader and StreamWriter: Here it is:
'You will need Imports System.IO
Dim TheNewFile As String
Dim MyLine As String
Dim MyStream2 As New FileStream("C:\Your Directory\YourFile.txt", FileMode.Open)
Dim MyReader As New StreamReader(MyStream2)
Dim MySettings As New StringReader(MyReader.ReadToEnd)
MyReader.BaseStream.Seek(0, SeekOrigin.Begin)
MyReader.Close()
MyStream2.Close()
Try
Do
MyLine = MySettings.ReadLine
'This if statement is an exit parameter. It can be if it contains or if 5 consecutive lines are nothing. It could be a number of things
If MyLine Is Nothing Then Exit Do
'This is the file you will write. You could do if MyLine = "Test" Then ........... append whatever and however you need to
TheNewFile = TheNewFile & MyLine & vbCrLf
Loop
Catch ex As Exception
MsgBox(ex.ToString())
End Try
'-----------------Write The new file!!!----------------
Dim MyStream3 As New FileStream("C:\Where you want to write New File\NewFileName.txt", FileMode.Create)
Dim MyWriter3 As New StreamWriter(MyStream3)
MyWriter3.Write(TheNewFile & "Test")
MyWriter3.Close()
MyStream3.Close()

Related

Trying to close textfile after line is read

Im trying to output the data from the second line of my textfile to a datagridview but when doing so it is also outputting every line after the the second line. This is what I have tried. Thanks
Dim lines = IO.File.ReadAllLines(OrderID & ".txt")
For index = 1 To lines.Length - 1
Dim cells = lines(index).Split(","c)
dgvOutput.Rows.Add(cells)
FileClose()
It's outputting every line after the second line, because that's what you're telling it to do when you iterate through the array of strings returns from ReadAllLines.
IO.File.ReadAllLines does not leave an output stream open. The file is closed. What it does do, is return a zero-based (by default) array of the contents of the file, with line breaks being the delimiter for the split.
To just get the contents of the second line, using ReadAllLines, this is what you need:
Dim lines = IO.File.ReadAllLines(OrderID & ".txt")
If lines.length >= 2 Then
Dim cells = lines(1).Split(","c)
dgvOutput.Rows.Add(cells)
End If
Now, that does have the overhead of reading the entire file in. If you open the file using a reader object, then you only need to read the first and second lines of the file to get that second line.
That would be something like this:
Dim reader as StreamReader = My.Computer.FileSystem.OpenTextFileReader(OrderId & ".txt")
Dim a as String
' This reads the first line, which we throw away
reader.ReadLine()
a = reader.ReadLine()
reader.Close()
Dim cells = a.Split(","c)
dgvOutput.Rows.Add(cells)
You would need to test your explicit circumstances to determine which is better for what you're trying to do.
Your loop is executed over all lines skipping just the first line.
While I cannot see what happen in the FileClose call it seems to not have any sense because ReadAllLines has already closed the file.
You can get the second line of your file with a single line of code
Dim line as String = File.ReadLines(OrderID & ".txt").Skip(1).Take(1).FirstOrDefault()
' this check is required to avoid problems with files containing 0 or 1 line
if line IsNot Nothing Then
Dim cells = line.Split(","c)
dgvOutput.Rows.Add(cells)
End If
Notice that I have replaced the ReadAllLines with ReadLines. This is better because using this method you don't read all lines when you need only the second one (if it exists). More info at ReadLines vs ReadAllLines
Dim lines = IO.File.ReadAllLines(OrderID & ".txt")
Dim SecondLine = lines(1)
File.ReadAllLines opens and closes the file for you so there is not need to add code to close it.

Using an array to search a file VB

I have a program that needs to look through a text file line by line, the lines look like this:
10-19-2015 Brett Reinhard All Bike Yoga Run the Studio Design Your Own Strength
These are separated by tabs in the text file.
What I want to do is look at the second value, in this case "Brett Reinhard" and move the full line to another textfile called "Brett Reinhard"
I was thinking of using an array to check to see if the second 'column' in the line matched any value within a given array, if it does I want to perform a specific action.
The way I am thinking of doing this is with a For/next statement, now while it will work it will be a laborious process for the computer that I will be using it on.
The code I am thinking of using looks like this:
For intCounter=0 to Whatever Number is the last number of the array
If currentfield.contains(array(intCounter)) Then
Open StreamWriter(File directory & array(intcounter) & ".txt")
Streamwriter.Writeline(currentfield)
End IF
Is there a better way of doing this, such as referencing the second 'column' in the line, similar to the syntax used in VBA for excel.
Name=Cells(1,2).Value
If you can guarantee that a line will only use the tab characters as field separators, you can do something along this:
Open the stream for reading text
Open a stream for writing text
Read a line of text
Use the Split method to break the incoming line into an array of fields
If the second element in the array is your sentinel value, write the original line to the writer
Repeat yourself until you have reached the end of file (ReadLine will return Nothing, or null for those c# folk).
Close and dispose of your stream objects.
If you aren't sure of the format, you will want to take the hit and use the TextFieldParser as mentioned in an earlier comment.
So while its not using an array to search a file, what I ended up doing works just as well. I ended up using the split method thanks to #Martin Soles.
Here is what I came up with:
Sub Main()
Dim intCount As Integer = 1
Dim words As String
Dim split As String()
Using MyReader As New Microsoft.VisualBasic.
FileIO.TextFieldParser(
"I:\Games, Events, & Promotions\FRP\Back End\Approved.txt")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
words = currentField
split = words.Split(New [Char]() {CChar(vbTab)})
For Each s As String In split
If intCount = 2 Then
Dim file As System.IO.StreamWriter
file = My.Computer.FileSystem.OpenTextFileWriter("I:\Games, Events, & Promotions\FRP\Back End\" & s & ".txt", True)
file.WriteLine(currentField)
file.Close()
End If
intCount = intCount + 1
Next s
intCount = 1
Next
Catch ex As Microsoft.VisualBasic.
FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
"is not valid and will be skipped.")
End Try
End While
End Using
End Sub 'Main
Thank you guys for the suggestions.
For right now the split method will work for what is needed.

Separating large file and inserting carriage returns based on string

New to VB.Net but a friend recommended that I used it for what I'm trying to do. I have a huge text file and I want to insert carriage returns in after a specific string.
Apart from the mess I have below , how would I alter this to read a file and then once we see the text "ext" insert a new line feed. I'm expecting one of the lines in the input file to produce alot of carriage returns.
Currently what I have managed to mock together below reads an input file until end of line and writes it out again into another file.
Module Module1
Sub Main()
Try
' Create an instance of StreamReader to read from a file.
' The using statement also closes the StreamReader.
Using sr As StreamReader = New StreamReader("C:\My Documents\input.txt")
Dim line As String
' Read and display lines from the file until the end of
' the file is reached.
Using sw As StreamWriter = New StreamWriter("C:\My Documents\output.txt")
Do Until sr.EndOfStream
line = sr.ReadLine()
sw.WriteLine(line)
Console.WriteLine("done")
Loop
End Using
End Using
Catch e As Exception
' Let the user know what went wrong.
Console.WriteLine("The file could not be read:")
Console.WriteLine(e.Message)
End Try
Console.ReadKey()
End Sub
Changes made following comments.. Falling over at 500mb files due to memory constraints:
Sub Main()
Try
' Create an instance of StreamReader to read from a file.
' The using statement also closes the StreamReader.
Using sr As StreamReader = New StreamReader("C:\My Documents\input.txt")
Dim line As String
Dim term As String = "</ext>"
' Read and display lines from the file until the end of
' the file is reached.
Using sw As StreamWriter = New StreamWriter("C:\My Documents\output.txt")
Do Until sr.EndOfStream
line = sr.ReadLine()
line = line.Replace(term, term + Environment.NewLine)
sw.WriteLine(line)
Console.WriteLine("done")
Loop
End Using
End Using
Since your lines are very big, you'll have to:
Read/Write one character at a time
Save the last x characters
If the last x characters are equal to your term, write a new line
Dim term As String = "</ext>"
Dim lastChars As String = "".PadRight(term.Length)
Using sw As StreamWriter = New StreamWriter("C:\My Documents\output.txt")
Using sr As New System.IO.StreamReader("C:\My Documents\input.txt")
While Not sr.EndOfStream
Dim buffer(1) As Char
sr.Read(buffer, 0, 1)
lastChars &= buffer(0)
lastChars = lastChars.Remove(0, 1)
sw.Write(buffer(0))
If lastChars = term Then
sw.Write(Environment.NewLine)
End If
End While
End Using
End Using
Note: This will not work with a Unicode file. This assume each characters are one byte.

StreamReader not finding end of file

I simply need to read lines from a text file and show them. When I run this I can see that id does what I want, but after it reads the last value it just shows a blank form on my screen and does not move on. It seems like it can't find the end of the file or something. I don't get an error.
Using sr As New System.IO.StreamReader(Application.StartupPath & "\myfile.cfg")
Dim Line As String = ""
Dim i As Integer = 0
Dim temp_array As Array
Do While Line IsNot Nothing
Line = sr.ReadLine
temp_array = Line.Split("=")
'MessageBox.Show(temp_array(0))
Loop
End Using
That is bad code because you're actually going to use Line before testing whether it's Nothing. Here are two good options for looping through the lines of a text file:
Using reader As New StreamReader(filePath)
Dim line As String
Do Until reader.EndOfStream
line = reader.ReadLine()
'...
Loop
End Using
For Each line In File.ReadLines(filePath)
'...
Next
As you can see, the second is far more concise but it does require .NET 4.0 or later.

Textfieldparser Delimiters

I'm currently busy coding a hangman game in VB.NET.
As a wordlist, I have a textfile containing 1520 words, each one seperated by a new line...
The best I could think of to get a random word is with a Randomize() function.
Then getting the word from the line # which was randomly generated.
Only to find out just now, that this method:
Using parser As New Microsoft.VisualBasic.FileIO.TextFieldParser_
("filepath")
parser.TextFieldType = FileIO.FieldType.Delimited
doesn't allow me to use a new line as a delimiter...
Considering all words have different lengths/widths, I can't use this either:
parser.TextFieldType = FileIO.FieldType.FixedWidth
Is there any better way for me to extract the word from that random line?
If not, what would be the delimiter I should use for this and how do I quickly change the breaklines into that new delimiter without resorting to Office?
Also, how can I use the textfieldparser to get the file from resources?
When I tried using
my.resources.filename
instead of "filepath", it gave me an ArgumentException due to "invalid characters in the path".
The easier way is to load your text file into a string collection, then grab the random index of the collection
Dim list As New List(Of String)
Dim Reader As New StreamReader("C:\WordList.txt")
Dim line As String
Do
line = Reader.ReadLine()
list.Add(line)
Loop Until line Is Nothing
Reader.Close()
Read all the words into a string array with File.ReadAllLines. One line of code:
Dim words() As String = File.ReadAllLines(path)
To select a random word, use Rnd
Randomize()
Dim randomWord As String = words(CInt(Math.Floor(Rnd * words.Length)))