Visual Basic - StreamWriter - How to skip to next line IF said line isn't empty - vb.net

Hey so I'm trying to do a simple StreamWriter for adding staff information to a text file (I already have a working StreamReader log in page) , the text file has some sample data but also must be able to have new data written to it.
My problem is that ONLY upon initial start up and my initial writing of data the information is written on the same line as the last line of sample data in the text file, not on the next blank line.
Here is how the text file looks after the first attempt to write data after start up.
Jon,Jones
Harry,Potter
James,Gunn
Kieran,Kieranson
Me,TooGreg,
"Me,Too" being my last line of sample data and "Grey,Hardy" being my first data written via StreamWriter
I've done some research on here and found examples of how to write a blank line which you could make the StreamWriter do every time to put spacing in between etc. but that doesn't work here as this problem only occurs the first time on any given start up and if it left a blank line every single time then if I made two attempts to use the StreamWriter it would look like
Jon,Jones
Harry,Potter
James,Gunn
Kieran,Kieranson
Me,Too
Greg,Hardy
BLANK LINE
Tom,Hardy
Which would then enable a blank log in to work.
Here is my code for the StreamWriter
'StreamReader to check if a line is empty or not
Dim StaffReader As StreamReader = File.OpenText("StaffInfo.txt")
strLine = StaffReader.ReadLine()
StaffReader.Close()
'Streamwriter for adding staff log in to textfile
Dim FileCheck As StreamWriter = File.AppendText("StaffInfo.txt")
FileCheck.WriteLine(strStaffUsername2 & "," & strStaffPass2)
FileCheck.Close(``)
MessageBox.Show(strStaffUsername2 & " added to the file. ", "Data Added")
txtUser2.Clear()
txtUser2.Focus()
txtPass2.Clear()
I just want it to skip to the next blank line if the line it is going to write on has any characters on it.

what you are looking for is the point, if the last line in your file contains a carriage return or not. If it does contain a carriage return, then you can append your text with your written code. But if it does not contain a carriage return, you have to prefix your first line with a carriage return.
Thus, first you have to check if your last line has a carriage return. You can do that by a function like this:
Private Function DoesLastLineHasCarriagReturn(Filename As String) As Boolean
Dim s as String = ""
using stream = New StreamReader(Filename)
' we have to read the last two characters
stream.BaseStream.Seek(-2,SeekOrigin.End)
dim c_beforeLast as Integer = stream.Read()
Dim c_Last As Integer = stream.Read()
' if the last character is 10 -> we have a carriage return. Windows and Linux just use different encodings
if (c_Last =10)
If(c_beforeLast = 13)
Console.WriteLine("Ends with carriage return CRLF (Windows)")
Else
Console.WriteLine("Ends with carriage return LF (UNIX, OSX )")
End If
return true
Else
Console.WriteLine("Does not end with Carriage return")
End If
End Using
return false
End Function
Then when beginning to write in the file, first you have to call the function. Here how your code could look like:
If DoesLastLineHasCarriagReturn("StaffInfo.txt")
Dim FileCheck As StreamWriter = File.AppendText("StaffInfo.txt")
FileCheck.WriteLine("Greg" & "," & "Hardy")
FileCheck.Close()
Else
Dim FileCheck As StreamWriter = File.AppendText("StaffInfo.txt")
FileCheck.WriteLine(vbCrLf + "Greg" & "," & "Hardy")
FileCheck.Close()
End If
By the way, I would recommend you to use the using statement to close the stream automatically:
If DoesLastLineHasCarriagReturn("StaffInfo.txt")
Using writer As New StreamWriter("StaffInfo.txt", True)
writer.WriteLine("Greg" & "," & "Hardy")
End Using
Else
Using writer As New StreamWriter("StaffInfo.txt", True)
writer.WriteLine(vbCrLf +"Greg" & "," & "Hardy")
End Using
End If

Since we are dealing with a text file and not doing anything fancy, we can just use the File class in System.IO.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim FilePath = "TestFiles/File1.txt"
'Dump contents of file
Dim fileContents As String = File.ReadAllText(FilePath)
'Extract the last 2 characters in the contents
Dim NextToLast As String = fileContents(fileContents.Length - 2)
Dim LastCharacter As String = fileContents(fileContents.Length - 1)
'Check if we have a CrLf an if not add a new line
If Not NextToLast = Chr(13) AndAlso Not LastCharacter = Chr(10) Then
File.WriteAllText(FilePath, Environment.NewLine)
End If
'Write to the file
File.AppendAllLines(FilePath, {TextBox1.Text})
End Sub
To display your text file, add a ListBox to your form.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
'Put the contents of the file into a string array of lines
Dim staff() As String = File.ReadAllLines("TestFiles/File1.txt")
ListBox1.DataSource = staff
End Sub

Related

Find word in a txt file and read previous line VB.NET

I am reading a txt file line by line in VB to look for the word "unable". That much works. The code is here:
Imports System
Imports System.IO
Imports PartMountCollector.HandMount_WebReference
Imports System.Threadingtime
Imports eCenter.Motor.VBConnect
Module Program
Sub Main(args As String())
Dim unUpdate As String = "Unable"
Dim time = DateTime.Now
Dim yesterday = time.AddDays(-1)
Dim format As String = "yyyyMMdd"
Dim words As String()
For Each Line As String In File.ReadLines("C:\Users\te-smtinternal\Desktop\ReStockLog\" + time.ToString(format) + ".txt")
words = Split(Line)
If Line.Contains(unUpdate) = True Then
Console.WriteLine("Exist")
'Read previous line looking for "Success"'
End If
Console.WriteLine("not found")
Next
End Sub
End Module
Now I need be able to identify this line and read the previous line, looking for the word "success".
Any help would be appreciated
Instead of trying to handle each line one at a time, you could read all the lines and then iterate through them which would give you access to the previous line, like:
Dim lines = IO.File.ReadAllLines(file_name)
dim previous_line as string = ""
for x as integer = 0 to lines.count-1
if lines(x).ToString.Contains("unable") then previous_line = lines(x-1).ToString
next
of course you would need to handle the exception of finding a hit on the first line which would throw an out of index error. So you would simply need to add a check to make sure x > 0.
You just need to declare a variable outside of the loop to store the previous line. Here I've named it previousLine...
Const unUpdate As String = "Unable"
Dim time = DateTime.Now
Const format As String = "yyyyMMdd"
Dim previousLine as String = Nothing
For Each currentLine As String In File.ReadLines("C:\Users\te-smtinternal\Desktop\ReStockLog\" + time.ToString(format) + ".txt")
If currentLine.Contains(unUpdate) Then
Console.WriteLine("Exist")
If previousLine Is Nothing Then
' The very first line of input contains unUpdate
Else If previousLine.Contains("Success")
' A line after the first line of input contains unUpdate
End If
Else
Console.WriteLine("not found")
End If
previousLine = currentLine
Next
At the end of each loop iteration the currentLine becomes the previousLine and, if there is another iteration, it will read a new value for currentLine.
Also note that in...
If Line.Contains(unUpdate) = True Then
...you don't need the = True comparison because Contains() already returns a Boolean.

How do I remove multiple empty lines in a text file

I wonder if someone is able to help. I have a m3u file with multiple lines of formatted text.
#EXTM3U
#RADIOBROWSERUUID:963194ef-0601-11e8-ae97-52543be04c81
#EXTINF:1,80s80s Christmas
http://streams.80s80s.de/christmas/mp3-192/streams.80s80s.de/
#RADIOBROWSERUUID:9638cfa5-0601-11e8-ae97-52543be04c81
#EXTINF:1,181.FM - Christmas Kountry
http://www.181.fm/stream/pls/181-xkkountry.pls
Whilst I have managed to extract the data into a format that I can need... I am left with multiple blank lines. A sample bit of code I used to Extract the data is...
If line.StartsWith("#EXTM3U") Then 'Remove
lines(i) = ""
End If
If line.StartsWith("#RADIOBROWSERUUID:") Then 'Remove
lines(i) = ""
End If
If line.StartsWith("#EXTINF:1,") Then 'Add # at beginning of line
lines(i) = line.Replace("#EXTINF:1,", "#")
End If
Which then leaves me with the following...
#80s80s Christmas
#http://streams.80s80s.de/christmas/mp3-192/streams.80s80s.de/
#181.FM - Christmas Kountry
#http://www.181.fm/stream/pls/181-xkkountry.pls
I just dont seem to be able to remove the empty/blank lines. I have used google as well as here and non of the answers seem to work for me. Here is the code that I am using...
Dim Newlines As String() = File.ReadAllLines(ofd.FileName)
For t As Integer = 0 To Newlines.Length - 1
Dim line2 As String = Newlines(t)
If line2.StartsWith("") Then ' Remove blank lines
Beep()
Newlines(t) = line2.Replace(Environment.NewLine, String.Empty)
End If
Next
File.WriteAllLines("NewTextm3u.txt", lines)
Can any body see where I am going wrong? Thank you very much.
You can do this:
Dim sFile As String = "c:\test2\test2.txt"
Dim Fdata As New List(Of String)
Fdata = File.ReadAllLines("c:\test2\test.txt").ToList
For i = Fdata.Count - 1 To 0 Step -1
If Fdata(i) = "" Then
Fdata.RemoveAt(i)
End If
Next
For Each sLine As String In Fdata
Debug.Print(sLine)
Next
File.WriteAllLines(sFile)
The above would remove all blank lines
In place of that loop, you could also use lamda expression like this:
Fdata.RemoveAll(Function(MyOneRow) MyOneRow = "")
I used the StrignSplitOptions.RemoveEmptyEntries to get rid of blank lines.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim FileContents = File.ReadAllText("SomeFile.txt")
Dim lines = FileContents.Split(Environment.NewLine.ToCharArray, StringSplitOptions.RemoveEmptyEntries)
End Sub
As you can see in the above image, there is what we can call an "enter" at the end of the sentence and another one between.
So let's just remove the one between the sentences and because it's just a line you can do it like this:
If line(i) = CHR(13) & CHR(10) then line(i)=""
but if you want to get a little paranoid and just want to remove all the "enters" or "line breaks" just do it like this:
line(i)=Replace(line(i),CHR(13) & CHR(10),"")

String Concatenation with Comma and Single Quotes E.g. ('ABC','DEF','GHI,'JKL')

I've been searching on internet how to Concatenate/Join Single quotes and comma on the String in vb.net's RichTextBox control. Example ('ABC','DEF','GHI,'JKL') I found this code online today it works even there's leading and trailing spaces and even lines are removed but the (' and ') are missing. Can you guys modify the code?
Code:
RichTextBox1.Text = Regex.Replace(RichTextBox1.Text.Trim, "\s+", "','")
Inside the RichTextBox1
ABC
DEF
GHI
JKL
Result: ABC','DEF','GHI','JKL
Desired Result: ('ABC','DEF','GHI','JKL')
As you can see, there are multiple ways this could be done. Here's another:
myRichTextBox.Text = $"('{String.Join("'," & ControlsChars.Lf & "'", myRichTextBox.Lines)}')"
Note that I have used ControlChars.Lf where I would usually use Environment.NewLine because the RichTextBox always uses that line break. I assume that it has something to do with the RTF format and compatibility.
Give this a try
' starting RichTextBox1 contains
' ABC
' DEF
' GHI
' JKL
Dim lns() As String = RichTextBox1.Lines
For x As Integer = 0 To lns.Length - 1
lns(x) = String.Format("'{0}',", lns(x))
Next
lns(0) = "(" & lns(0)
lns(lns.Length - 1) = lns(lns.Length - 1).TrimEnd(","c)
lns(lns.Length - 1) &= ")"
RichTextBox1.Lines = lns
Not knowing how many lines you are dealing with in a real scenario, I chose to use a StringBuilder. It creates mutable (changeable) strings saving us throwing away and recreating strings many times.
Start off the sb with the initial "(". Then the loop uses an interpolated string with an embedded variable for each line. AppendLine will add a new line after the text.
Lastly we display the new string. In .net we can string the dot notation working left to right. First convert the StringBuilder back to an actual String with .ToString. Next we clean up the end of the new string by removing the final comma and the final new line. A new line is actually composed of 2 Chars, carriage return and line feed. Lastly I added the final ")"
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lines() = File.ReadAllLines("some text file path")
Dim sb As New StringBuilder
sb.Append("(")
For Each line In lines
sb.AppendLine($"'{line}',")
Next
RichTextBox1.Text = sb.ToString.Trim({","c, Convert.ToChar(13), Convert.ToChar(10)}) & ")"
End Sub

Select text between key words

This is a follow on question to Select block of text and merge into new document
I have a SGM document with comments added and comments in my sgm file. I need to extract the strings in between the start/stop comments so I can put them in a temporary file for modification. Right now it's selecting everything including the start/stop comments and data outside of the start/stop comments.
Dim DirFolder As String = txtDirectory.Text
Dim Directory As New IO.DirectoryInfo(DirFolder)
Dim allFiles As IO.FileInfo() = Directory.GetFiles("*.sgm")
Dim singleFile As IO.FileInfo
Dim Prefix As String
Dim newMasterFilePath As String
Dim masterFileName As String
Dim newMasterFileName As String
Dim startMark As String = "<!--#start#-->"
Dim stopMark As String = "<!--#stop#-->"
searchDir = txtDirectory.Text
Prefix = txtBxUnique.Text
For Each singleFile In allFiles
If File.Exists(singleFile.FullName) Then
Dim fileName = singleFile.FullName
Debug.Print("file name : " & fileName)
' A backup first
Dim backup As String = fileName & ".bak"
File.Copy(fileName, backup, True)
' Load lines from the source file in memory
Dim lines() As String = File.ReadAllLines(backup)
' Now re-create the source file and start writing lines inside a block
' Evaluate all the lines in the file.
' Set insideBlock to false
Dim insideBlock As Boolean = False
Using sw As StreamWriter = File.CreateText(backup)
For Each line As String In lines
If line = startMark Then
' start writing at the line below
insideBlock = True
' Evaluate if the next line is <!Stop>
ElseIf line = stopMark Then
' Stop writing
insideBlock = False
ElseIf insideBlock = True Then
' Write the current line in the block
sw.WriteLine(line)
End If
Next
End Using
End If
Next
This is the example text to test on.
<chapter id="Chapter_Overview"> <?Pub Lcl _divid="500" _parentid="0">
<title>Learning how to gather data</title>
<!--#start#-->
<section>
<title>ALTERNATE MISSION EQUIPMENT</title>
<para0 verdate="18 Jan 2019" verstatus="ver">
<title>
<applicabil applicref="xxx">
</applicabil>Three-Button Trackball Mouse</title>
<para>This is the example to grab all text between start and stop comments.
</para></para0>
</section>
<!--#stop#-->
Things to note: the start and stop comments ALWAYS fall on a new line, a document can have multiple start/stop sections
I thought maybe using a regex on this
(<section>[\w+\w]+.*?<\/section>)\R(<\?Pub _gtinsert.*>\R<pgbrk pgnum.*?>\R<\?Pub /_gtinsert>)*
Or maybe use IndexOf and LastIndexOf, but I couldn't get that working.
You can read the entire file and split it into an array using the string array of {"<!--#start#-->", "<!--#stop#-->"} to split, into this
Element 0: Text before "<!--#start#-->"
Element 1: Text between "<!--#start#-->" and "<!--#stop#-->"
Element 2: Text after "<!--#stop#-->"
and take element 1. Then write it to your backup.
Dim text = File.ReadAllText(backup).Split({startMark, stopMark}, StringSplitOptions.RemoveEmptyEntries)(1)
Using sw As StreamWriter = File.CreateText(backup)
sw.Write(text)
End Using
Edit to address comment
I did make the original code a little compact. It can be expanded out into the following, which allows you to add some validation
Dim text = File.ReadAllText(backup)
Dim split = text.Split({startMark, stopMark}, StringSplitOptions.RemoveEmptyEntries)
If split.Count() <> 3 Then Throw New Exception("File didn't contain one or more delimiters.")
text = split(1)
Using sw As StreamWriter = File.CreateText(backup)
sw.Write(text)
End Using

Get only the line of text that contains the given word VB2010.net

I have a text file on my website and I download the whole string via webclient.downloadstring.
The text file contains this :
cookies,dishes,candy,(new line)
back,forward,refresh,(new line)
mail,media,mute,
This is just an example it's not the actual string , but it will do for help purposes.
What I want is I want to download the whole string , find the line that contains the word that was entered by the user in a textbox, get that line into a string, then I want to use the string.split with as delimiter the "," and output each word that is in the string into an richtextbox.
Now here is the code that I have used (some fields are removed for privacy reasons).
If TextBox1.TextLength > 0 Then
words = web.DownloadString("webadress here")
If words.Contains(TextBox1.Text) Then
'retrieval code here
Dim length As Integer = TextBox1.TextLength
Dim word As String
word = words.Substring(length + 1) // the plus 1 is for the ","
Dim cred() As String
cred = word.Split(",")
RichTextBox1.Text = "Your word: " + cred(0) + vbCr + "Your other word: " + cred(1)
Else
MsgBox("Sorry, but we could not find the word you have entered", MsgBoxStyle.Critical)
End If
Else
MsgBox("Please fill in an word", MsgBoxStyle.Critical)
End If
Now it works and no errors , but it only works for line 1 and not on line 2 or 3
what am I doing wrong ?
It's because the string words also contains the new line characters that you seem to be omitting in your code. You should first split words with the delimiter \n (or \r\n, depending on the platform), like this:
Dim lines() As String = words.Split("\n")
After that, you have an array of strings, each element representing a single line. Loop it through like this:
For Each line As String In lines
If line.Contains(TextBox1.Text) Then
'retrieval code here
End If
Next
Smi's answer is correct, but since you're using VB you need to split on vbNewLine. \n and \r are for use in C#. I get tripped up by that a lot.
Another way to do this is to use regular expressions. A regular expression match can both find the word you want and return the line that contains it in a single step.
Barely tested sample below. I couldn't quite figure out if your code was doing what you said it should be doing so I improvised based on your description.
Imports System.Text.RegularExpressions
Public Class Form1
Private Sub ButtonFind_Click(sender As System.Object, e As System.EventArgs) Handles ButtonFind.Click
Dim downloadedString As String
downloadedString = "cookies,dishes,candy," _
& vbNewLine & "back,forward,refresh," _
& vbNewLine & "mail,media,mute,"
'Use the regular expression anchor characters (^$) to match a line that contains the given text.
Dim wordToFind As String = TextBox1.Text & "," 'Include the comma that comes after each word to avoid partial matches.
Dim pattern As String = "^.*" & wordToFind & ".*$"
Dim rx As Regex = New Regex(pattern, RegexOptions.Multiline + RegexOptions.IgnoreCase)
Dim M As Match = rx.Match(downloadedString)
'M will either be Match.Empty (no matching word was found),
'or it will be the matching line.
If M IsNot Match.Empty Then
Dim words() As String = M.Value.Split(","c)
RichTextBox1.Clear()
For Each word As String In words
If Not String.IsNullOrEmpty(word) Then
RichTextBox1.AppendText(word & vbNewLine)
End If
Next
Else
RichTextBox1.Text = "No match found."
End If
End Sub
End Class