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 - vb.net

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

Related

How to search multiple text files in a directory for a string of text at once

I have a ListBox with a certain amount of items in it.
For each item in the ListBox a corresponding text file exists in the file directory.
I need to search each text file (based on what's in the ListBox) for a persons name. Each text file may contain the name or it may not.
I would then like a return which text file contains the name.
I have tried this as a way to search a text file: it works, but I'm not sure how to get this to repeat based on whats in a ListBox.
Dim sFileContents As String = String.Empty
If (System.IO.File.Exists((Application.StartupPath) & "\Project_Green.txt")) Then
sFileContents = (System.IO.File.ReadAllText((Application.StartupPath) & "\Project_Green.txt"))
End If
If sFileContents.Contains(TextBox4.Text) Then
MessageBox.Show("yup")
Else
MessageBox.Show("nope")
End If
Also, if it would be possible to ignore case that would be great.
If you have a bunch of files in a directory and you have their names in a ListBox, and you want to search their contents for something.
One liner query:
Imports System.IO
'...
Sub TheCaller()
Dim dir = My.Application.Info.DirectoryPath
Dim ext = ".txt" ' If the extensions are trimmed in the list.
Dim find = TextBox4.Text
Dim files = Directory.EnumerateFiles(dir).Where(Function(x) ListBox1.Items.Cast(Of String).
Any(Function(y) String.Concat(y, ext).
Equals(Path.GetFileName(x),
StringComparison.InvariantCultureIgnoreCase) AndAlso File.ReadLines(x).
Any(Function(z) z.IndexOf(find, StringComparison.InvariantCultureIgnoreCase) >= 0))).ToList
ListBox2.Items.Clear()
ListBox2.Items.AddRange(files.Select(Function(x) Path.GetFileNameWithoutExtension(x)).ToArray)
End Sub
Or if you prefer the For Each loop:
Sub Caller()
Dim dir = My.Application.Info.DirectoryPath
Dim find = TextBox4.Text
Dim files As New List(Of String)
For Each f As String In ListBox1.Items.Cast(Of String).
Select(Function(x) Path.Combine(dir, $"{x}.txt"))
If File.Exists(f) AndAlso
File.ReadLines(f).Any(Function(x) x.IndexOf(find,
StringComparison.InvariantCultureIgnoreCase) <> -1) Then
files.Add(f)
End If
Next
ListBox2.Items.Clear()
ListBox2.Items.AddRange(files.Select(Function(x) Path.GetFileNameWithoutExtension(x)).ToArray)
End Sub
Either way, the files list contains the matches if any.
Plus a pseudo-parallel async method, for the very heavy-duty name searches.
The Async Function SearchNameInTextFiles returns a named Tuple:
(FileName As String, Index As Integer)
where FileName is the file parsed and Index is the position where the first occurrence of the specified name (theName) was found.
If no matching sub-string is found, the Index value is set to -1.
The caseSensitive parameter allows to specify whether the match should be, well, case sensitive.
You can start the search from a Button.Click async handler (or similar), as shown here.
Imports System.IO
Imports System.Threading.Tasks
Private Async Sub btnSearchFiles_Click(sender As Object, e As EventArgs) Handles btnSearchFiles.Click
Dim filesPath = [Your files path]
Dim theName = textBox4.Text ' $" {textBox4.Text} " to match a whole word
Dim ext As String = ".txt" ' Or String.Empty, if extension is already included
Dim tasks = ListBox1.Items.OfType(Of String).
Select(Function(f) SearchNameInTextFiles(Path.Combine(filesPath, f & ext), theName, False)).ToList()
Await Task.WhenAll(tasks)
Dim results = tasks.Where(Function(t) t.Result.Index >= 0).Select(Function(t) t.Result).ToList()
results.ForEach(Sub(r) Console.WriteLine($"File: {r.FileName}, Position: {r.Index}"))
End Sub
Private Async Function SearchNameInTextFiles(filePath As String, nameToSearch As String, caseSensitive As Boolean) As Task(Of (FileName As String, Index As Integer))
If Not File.Exists(filePath) then Return (filePath, -1)
Using reader As StreamReader = New StreamReader(filePath)
Dim line As String = String.Empty
Dim linesLength As Integer = 0
Dim comparison = If(caseSensitive, StringComparison.CurrentCulture,
StringComparison.CurrentCultureIgnoreCase)
While Not reader.EndOfStream
line = Await reader.ReadLineAsync()
Dim position As Integer = line.IndexOf(nameToSearch, comparison)
If position > 0 Then Return (filePath, linesLength + position)
linesLength += line.Length
End While
Return (filePath, -1)
End Using
End Function
You can do these simple steps for your purpose:
First get all text files in the application's startup directory.
Then iterate over all names in the ListBox and for each one, search in all text files to find the file that contains that name.
To make the process case-insensitive, we first convert names and text file's contents to "lower case" and then compare them. Here is the full code:
Private Sub findTextFile()
'1- Get all text files in the directory
Dim myDirInfo As New IO.DirectoryInfo(Application.StartupPath)
Dim allTextFiles As IO.FileInfo() = myDirInfo.GetFiles("*.txt")
'2- Iterate over all names in the ListBox
For Each name As String In ListBox1.Items
'Open text files one-by-one and find the first text file that contains this name
Dim found As Boolean = False 'Changes to true once the name is found in a text file
Dim containingFile As String = ""
For Each file As IO.FileInfo In allTextFiles
If System.IO.File.ReadAllText(file.FullName).ToLower.Contains(name.ToLower) Then 'compares case-insensitive
found = True
containingFile = file.FullName
Exit For
End If
Next
'Found?
If found Then
MsgBox("The name '" + name + "' found in:" + vbNewLine + containingFile)
Else
MsgBox("The name '" + name + "' does not exist in any text file.")
End If
Next
End Sub

VB.net file handling progresses to slowly

Hi i have a app that takes a list of files and searches each file for all the images referenced within each file. When the list is finished I sort and remove duplicates from the list then copy each item/image to a new folder. It works, but barely. I takes hours for the copying to occur on as little as 500 files. Doing the copying in windows explorer if faster, and that defeats the purpose of the application.
I don't know how to streamline it better. Your inputs would be greatly appreciated.
'Remove Dupes takes the list of images found in each file and removes any duplicates
Private Sub RemoveDupes(ByRef Items As List(Of String), Optional ByVal NeedSorting As Boolean = False)
statusText = "Removing duplicates from list."
Dim Temp As New List(Of String)
Items.Sort()
'Remove Duplicates
For Each Item As String In Items
'Check if item is in Temp
If Not Temp.Contains(Item) Then
'Add item to list.
Temp.Add(Item)
File.AppendAllText(ListofGraphics, Item & vbNewLine)
End If
Next Item
'Send back new list.
Items = Temp
End Sub
'GetImages does the actual copying of files from the list RemoveDup creates
Public Sub GetImages()
Dim imgLocation = txtSearchICN.Text
' Get the list of file
Dim fileNames As String() = System.IO.Directory.GetFiles(imgLocation)
Dim i As Integer
statusText = "Copying image files."
i = 0
For Each name As String In GraphicList
i = i + 1
' See whether name appears in fileNames.
Dim found As Boolean = False
' Search name in fileNames.
For Each fileName As String In fileNames
' GraphicList consists of filename without extension, so we compare name
' with the filename without its extension.
If Path.GetFileNameWithoutExtension(fileName) = name Then
Dim FileNameOnly = Path.GetFileName(fileName)
' Debug.Print("FileNameOnly: " & FileNameOnly)
Dim copyTo As String
copyTo = createImgFldr & "\" & FileNameOnly
System.IO.File.Copy(fileName, copyTo)
File.AppendAllText(ListofFiles, name & vbNewLine)
'items to write to rich text box in BackgroundWorker1_ProgressChanged
imgFilename = (name) + vbCrLf
ImageCount1 = i
' Set found to True so we do not process name as missing, and exit For. \
found = True
Exit For
Else
File.AppendAllText(MissingFiles, name & vbNewLine)
End If
Next
status = "Copying Graphic Files"
BackgroundWorker1.ReportProgress(100 * i / GraphicList.Count())
Next
End Sub
'BackgroundWorker1_ProgressChanged. gets file counts and writes to labels and rich text box
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
'' This event is fired when you call the ReportProgress method from inside your DoWork.
'' Any visual indicators about the progress should go here.
ProgressBar1.Value = e.ProgressPercentage
lblStatus.Text = CType(e.UserState, String)
lblStatus.Text = status & " " & e.ProgressPercentage.ToString & " % Complete "
RichTextBox1.Text &= (fileFilename)
RichTextBox1.Text &= (imgFilename)
txtImgCount.Text = ImageCount1
Label8.Text = statusText
fileCount.Text = fCount
End Sub
I would change something in your code to avoid the constant writing to a file at each loop and the necessity to have two loops nested.
This is a stripped down version of your GetFiles intended to highlight my points:
Public Sub GetImages()
' Two list to collect missing and found files
Dim foundFiles As List(Of String) = New List(Of String)()
Dim notfoundFiles As List(Of String) = New List(Of String)()
Dim fileNames As String() = System.IO.Directory.GetFiles(imgLocation)
' Loop over the filenames retrieved
For Each fileName As String In fileNames
' Check if the files is contained or not in the request list
If GraphicList.Contains(Path.GetFileNameWithoutExtension(fileName)) Then
Dim FileNameOnly = Path.GetFileName(fileName)
Dim copyTo As String
copyTo = createImgFldr & "\" & FileNameOnly
System.IO.File.Copy(fileName, copyTo)
' Do not write to file inside the loop, just add the fact to the list
foundFiles.Add(FileNameOnly)
Else
notfoundFiles.Add(FileNameOnly)
End If
Next
' Write everything outside the loop
File.WriteAllLines(listofFiles, foundFiles)
File.WriteAllLines(MissingFiles, notfoundFiles)
End Sub

Read line where is specific word in txt file

I need to read the Config file for load settings.
My code:
Dim preferences As FileInfo
preferences = New FileInfo(".\settings.conf")
If preferences.Exists Then
Dim objReader As New System.IO.StreamReader(".\settings.conf")
Dim tmpLine_theme As String
Do While objReader.Peek() <> -1
tmpLine_theme = objReader.ReadLine()
If tmpLine_theme.StartsWith("theme_selected: ") Then
tmpLine_theme = tmpLine_theme.Replace("theme_selected: ", "")
theme_box.Text = tmpLine_theme
MsgBox("Theme:" + tmpLine_theme)
theme_selected_var = tmpLine_theme
Else
MsgBox("Not working")
End If
Loop
This code causes a loop, through which can't go on.
I need to get the specific word, which then removes and retrieves the required data.
If i get you correctly,you are trying to get the line which contains specific word ? It isn't that hard , just a few lines of code :)
Dim readFile as New List(of String)(File.ReadAllLine("path of file"))
For each line in readFile
If line.Contains("theme_selected: ") Then
line.Replace("theme_selected: ","")
MsgBox(line)
End if
Next

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.net showdialog openfile to string

i'm trying to importe a csv file after creating on the same application, the only probleme is that even if a string matchs a line from the file, comparing them on vb.net dosn't give a true boolean i know i didn't make any mistakes because of the line with the commentary 'THIS LINE , i use a pretty small list to do my test and in that loop, there is always one element that matches exactly the string, but comparing them on vb.net dosn't return a true. the result of this is that just after saving the file to my computer while still having it on my listview1 on the application, i load it to the application again and it duplicates everything
Dim open As New OpenFileDialog
open.Filter = "CSV Files (*.csv*)|*.csv"
If open.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim File As String = My.Computer.FileSystem.ReadAllText(open.FileName)
Dim lines() As String = File.Split(Environment.NewLine)
For i = 1 To (lines.Count - 1)
Dim line As String = lines(i)
Dim Columns() As String = line.Split(";")
Dim addLin As New ListViewItem(Columns)
Dim Alr As Boolean = False
Dim st as string=listView1.Items.Item(k).SubItems.Item(0).Text
For k = 0 To (ListView1.Items.Count - 1)
Dim st as string=listView1.Items.Item(k).SubItems.Item(0).Text
MsgBox(Columns(0)& Environment.NewLine & st) 'THIS LINE
If ListView1.Items.Item(k).SubItems.Item(0).Text = Columns(0) Then
Alr = True
MsgBox("true") 'never showsup even when the previous one show the match
End If
next
If Alr = False Then
MsgBox("false") 'the msgbox is only to check
ListView1.Items.Add(addLin)
End If
next
end if