Trying to delete a line in a text file -VB - vb.net

I'm very new to coding so any help is appreciated.
I've created a simple listbox that displays an array from a text file.
I wanted to add a textbox and a delete button so the user can type a word and then delete that line from the text file.
I've read many forums with various solutions for this but all have returned errors - currently I am getting this error: "System.IO.IOException: 'The process cannot access the file 'C:\Users\hches\source\repos\Inventory\Inventory\bin\Debug\Stock.txt' because it is being used by another process.'"
in sub DeleteLine()
Here is the relevant code to the Delete button and the respective DeleteLine() sub:
Private Sub BTDel_Click(sender As Object, e As EventArgs) Handles BTDel.Click
Dim sr As New StreamReader("Stock.txt")
Dim i As Integer = 0
Dim deleted As Boolean = False
If TBSearch.Text = "" Then
MsgBox("Please enter an Item to Delete.")
Else
Do Until sr.Peek() = -1 Or deleted = True 'prevents it from looping through the whole stock if the item is deleted
Dim Itm As String = sr.ReadLine()
If Itm.Contains(TBSearch.Text) Or Itm.ToLower.Contains(TBSearch.Text.ToLower) Then 'if the line read from the text contains the search word, continue
MsgBox(TBSearch.Text & " has been deleted.") 'simple messagebox says it has been deleted
DeleteLine()
deleted = True
TBSearch.Clear()
ElseIf sr.Peek() = -1 Then 'if it reaches the end of the document and it hasn't been found
MsgBox("Item has not been deleted.") 'message box appears saying it is not deleted
deleted = False
TBSearch.Clear()
End If
i = i + 1
Loop
End If
End Sub
Public Sub DeleteLine()
Dim line As Integer = 0
Dim Filename = "Stock.txt"
Dim TheFileLines As New List(Of String)
For line = 0 To TheFileLines.Count
TheFileLines.AddRange(System.IO.File.ReadAllLines(Filename))
' if line is beyond end of list then exit sub
If line >= TheFileLines.Count Then Exit Sub
TheFileLines.RemoveAt(line)
System.IO.File.WriteAllLines(Filename, TheFileLines.ToArray)
Next
End Sub
Many thanks for any guidance,
Henry
SOLVED -- For anyone interested I will post my solution, thanks for the help.
Public Sub DeleteLine()
ArrayLoad() 'populates my array from text file
File.Delete("Stock.txt") 'deletes original text file
Dim stockList As List(Of String) = ItemNames.ToList 'creates a list using my array
stockList.Remove(TBSearch.Text) 'removes the searched item from the list
File.Create("Stock.txt").Dispose() 'creates a new text file (same name as the original so the program will work fine)
Using sw As New StreamWriter("Stock.txt") 'sets up a streamwriter to write the new list to the text file
For Each item As String In stockList
sw.WriteLine(item)
Next
sw.Flush()
sw.Close()
End Using
End Sub
End Class

Related

Drag and Drop to Outlook Message to Windows Form

I currently have a Windows Forms application that accepts drag and dropped files from other applications. Everything seemed to be working smoothly until we discovered that if we added an email attached to an email, then things got weird.
For example, users had no problem dragging attached jpg or pdf files directly from emails into the application. But when an email (.msg file) was attached to an email, and it was the attached email that was trying to be added to the program, then here's what happens: the following code is able to correctly read the name of the selected attachment that was dragged into the program, but the actual file that is copied is the main containing e-mail (including all the attachments).
Is there any way that I can just pull out the selected/dragged message?
Thanks!!
Here's the entire function:
Public Shared Function HandleFileDrops(ByVal e As System.Windows.Forms.DragEventArgs) As String
' Based on and Borrowed from http://allandynes.com/2015/10/vb-net-drag-and-drop-from-outlook/
Try
If e.Data.GetDataPresent(DataFormats.FileDrop) Then
' We have a file so lets pass it to the calling form
Dim Filename As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())
HandleFileDrops = Filename(0)
ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then
' We have a embedded file. First lets try to get the file name out of memory
Dim theStream As IO.Stream = CType(e.Data.GetData("FileGroupDescriptor"), IO.Stream)
Dim fileGroupDescriptor(512) As Byte
theStream.Read(fileGroupDescriptor, 0, 512)
Dim fileName As System.Text.StringBuilder = New System.Text.StringBuilder("")
Dim i As Integer = 76
While Not (fileGroupDescriptor(i) = 0)
fileName.Append(Convert.ToChar(fileGroupDescriptor(i)))
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
theStream.Close()
' We should have the file name or if its an email, the subject line. Create our temp file based on the temp path and this info
Dim myTempFile As String = IO.Path.GetTempPath & fileName.ToString
' Look to see if this is a email message. If so save that temporarily and get the temp file.
If InStr(myTempFile, ".msg") > 0 Then
Dim objOL As New Microsoft.Office.Interop.Outlook.Application
Dim objMI As Microsoft.Office.Interop.Outlook.MailItem
If objOL.ActiveExplorer.Selection.Count > 1 Then
MsgBox("You can only drag and drop one item at a time into this screen. Only the first item you selected will be used.", MsgBoxStyle.OkOnly Or MsgBoxStyle.Information, "One Item At A Time")
End If
For Each objMI In objOL.ActiveExplorer.Selection()
objMI.SaveAs(myTempFile)
Exit For
Next
objOL = Nothing
objMI = Nothing
Else
' If its a attachment we need to pull the file itself out of memory
Dim ms As IO.MemoryStream = CType(e.Data.GetData("FileContents", True), IO.MemoryStream)
Dim FileBytes(CInt(ms.Length)) As Byte
' read the raw data into our variable
ms.Position = 0
ms.Read(FileBytes, 0, CInt(ms.Length))
ms.Close()
' save the raw data into our temp file
Dim fs As IO.FileStream = New IO.FileStream(myTempFile, IO.FileMode.OpenOrCreate, IO.FileAccess.Write)
fs.Write(FileBytes, 0, FileBytes.Length)
fs.Close()
End If
' Make sure we have a actual file and also if we do make sure we erase it when done
If IO.File.Exists(myTempFile) Then
' Assign the file name to the add dialog
HandleFileDrops = myTempFile
Else
HandleFileDrops = String.Empty
End If
Else
Throw New System.Exception("An exception has occurred.")
End If
Catch ex As Exception
MsgBox("Could not copy file from memory. Please save the file to your hard drive first and then retry your drag and drop.", MsgBoxStyle.OkOnly Or MsgBoxStyle.Information, "Drag and Drop Failed")
HandleFileDrops = String.Empty
End Try
End Function
This is the section in particular that handles the e-mail:
Dim objOL As New Microsoft.Office.Interop.Outlook.Application
Dim objMI As Microsoft.Office.Interop.Outlook.MailItem
If objOL.ActiveExplorer.Selection.Count > 1 Then
MsgBox("You can only drag and drop one item at a time into this screen. Only the first item you selected will be used.", MsgBoxStyle.OkOnly Or MsgBoxStyle.Information, "One Item At A Time")
End If
For Each objMI In objOL.ActiveExplorer.Selection()
objMI.SaveAs(myTempFile)
Exit For
Next
objOL = Nothing
objMI = Nothing
After really looking at the code that I borrowed from elsewhere on the web, I now see exactly what it does. The section of code that saves Outlook messages creates a new instance of the current Outlook object and then calls that object to pull in its selected items, which will happen to be the main selected email - not the attached email that was dragged over. I was able to add a couple lines of code to do some comparisons on either the email or attachment name to see what was what.
This now works well for my needs:
Dim objOL As New Microsoft.Office.Interop.Outlook.Application
Dim objMI As Microsoft.Office.Interop.Outlook.MailItem
If objOL.ActiveExplorer.Selection.Count > 1 Then
MsgBox("You can only drag and drop one item at a time into this screen. Only the first item you selected will be used.", MsgBoxStyle.OkOnly Or MsgBoxStyle.Information, "One Item At A Time")
End If
'If the message itself has the same name as fileName, then just save the selected MailObject
'Otherwise, iterate through all the attachments to the MailObject and save the one that hase that same name as the fileName
For Each objMI In objOL.ActiveExplorer.Selection()
If objMI.Subject = fileName.ToString() Then
objMI.SaveAs(myTempFile)
Else
Dim objAttach As Microsoft.Office.Interop.Outlook.Attachments = objMI.Attachments
For Each attach As Microsoft.Office.Interop.Outlook.Attachment In objAttach
If attach.FileName = fileName.ToString() Then
attach.SaveAsFile(myTempFile)
End If
Next
End If
Exit For
Next
objOL = Nothing
objMI = Nothing

How to Save, Separate, and Write Data from File to Multiple TextBoxes

I need to save a bunch (around 600) of TextBox content to a (Preferably) single file, then be able to write that data back to their respective TextBoxes on file open. Essentially I'm making a D&D stat sheet, and I want to save what each player has entered as the [character's name].txt. I already got simple saving and writing down by using a single control and the code:
Dim SaveCharacter As StreamWriter
If txtName.Text = "" Then
MessageBox.Show("In order to save, you must enter a name for your character.", "Error: No Name Entered")
Else
Try
SaveCharacter = File.AppendText("H:\Visual Basic Projects\DAndD-2.5\DAndD-2.5\Saves\" & txtName.Text & ".txt")
SaveCharacter.WriteLine(frmNotes.rtxNotes.Text)
SaveCharacter.Close()
Catch
MessageBox.Show("Error")
End Try
End If
'Next event handler
Dim OpenCharacter As StreamReader
OpenCharacter = File.OpenText("H:\Visual Basic Projects\DAndD-2.5\DAndD-2.5\Saves\Jared.txt")
Do Until OpenCharacter.EndOfStream
frmNotes.rtxNotes.Text = OpenCharacter.ReadToEnd.ToString()
For Each strLine As String In frmNotes.rtxNotes.Text.Split(vbNewLine)
Next
Loop
Is there an easy(ish) way to do what I need, especially in mass (few lines of code) without having to save each TextBox as a different .txt file?
Thanks for the help!
Loop through all the controls and pull out the TextBoxes:
Sub SaveFile(strFilename As String)
Using fs As New System.IO.FileStream(strFilename, IO.FileMode.OpenOrCreate)
Using sr As New System.IO.StreamWriter(fs)
For Each ctl As Control In Me.Controls
If TypeOf ctl Is TextBox Then
Dim txt As TextBox = DirectCast(ctl, TextBox)
sr.WriteLine(txt.Name & ":" & txt.Text)
End If
Next ctl
End Using
End Using
End Sub
Sub Readfile(strfilename As String)
Using fs As New System.IO.FileStream(strfilename, IO.FileMode.Open)
Using sr As New System.IO.StreamReader(fs)
Do Until sr.EndOfStream
Dim strLine As String = sr.ReadLine
Dim colonposition As Integer = strLine.IndexOf(":")
If colonposition > 0 And colonposition < strLine.Length - 1 Then
Dim strTextBoxName As String = strLine.Substring(0, colonposition)
Dim strTextBoxText As String = strLine.Substring(colonposition + 1)
Dim ctl() As Control = Me.Controls.Find(strTextBoxName, False)
If ctl.Length > 0 AndAlso TypeOf ctl(0) Is TextBox Then
DirectCast(ctl(0), TextBox).Text = strTextBoxText
End If
End If
Loop
End Using
End Using
End Sub
The above code only works for textboxes on the form itself. You can rework it to be a recursive function to walk the containers, but I'll leave that as an exercise for the reader.
This will write the contents of all your TextBoxes to a file, one line per control:
IO.File.WriteAllLines(filePath, Me.Controls.OfType(Of TextBox).Select(Function(tb) tb.Text))
This will read a file back into those TextBoxes:
Dim textBoxes = Me.Controls.OfType(Of TextBox).ToArray()
Dim lines = IO.File.ReadAllLines(filePath)
For i = 0 To lines.GetUpperBound(0)
textBoxes(i).Text = lines(i)
Next
That assumes that no TextBoxes are multi-line and it also does not validate the file on reading, so you might want to check that the number of lines and TextBoxes matches.

How do I speed up searching through files on a network drive and prevent "not responding" in VB.Net

Part of my application searches for a string provided by a textbox within .txt files and .pdf files stored on a network drive. It works great on my PC when looking within a directory of a few files stored on a local disk, when I run it on my work PC which is less beefy and looking at a network drive I get "not responding" and it takes a good few minutes to finally wake up again. This is only searching through around 100 files and that number is only going to get bigger.
I thought about adding a progress bar, but if the application is not responding I assume the progress bar will not update? I would be very grateful to hear the advice of someone much more experienced in this than me.
In short, the code searches as described above, uses the name of the folder (that begins with SCC) to add an item to a listbox. If it cannot search the PDF for any reason then it adds it to another listbox displaying the folder names it was unable to search.
Here is the section of code that does the search:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim path As String = ""
Dim list As System.Collections.ObjectModel.ReadOnlyCollection(Of String)
Dim raf As itextsharp.text.pdf.RandomAccessFileOrArray = Nothing
Dim reader As itextsharp.text.pdf.PdfReader = Nothing
Dim searchPhrase As String = faultSearch.Text
VINListBox.Items.Clear()
Region "search plain text"
'finds text within faultSearch textbox within the files in directory
list = My.Computer.FileSystem.FindInFiles(archive_dir, faultSearch.Text, True, FileIO.SearchOption.SearchAllSubDirectories)
For Each foundFile As String In list
path = foundFile
GetVinName(path)
Next
End Region
Region "search PDF"
'Finds text within faultSearch textbox within PDF files in directory
For Each file As String In My.Computer.FileSystem.GetFiles(archive_dir, FileIO.SearchOption.SearchAllSubDirectories)
If System.IO.Path.GetExtension(file).ToUpper = ".PDF" Then
Try
raf = New itextsharp.text.pdf.RandomAccessFileOrArray(file)
reader = New itextsharp.text.pdf.PdfReader(raf, Nothing)
For i As Integer = 1 To reader.NumberOfPages()
Dim pageText As String = itextsharp.text.pdf.parser.PdfTextExtractor.GetTextFromPage(reader, i)
If pageText.ToUpper.Contains(searchPhrase) Then
GetVinName(file)
End If
Next
Catch ex As Exception
GetErrVinName(file)
End Try
End If
Next
End Sub
End Region
Private Sub GetVinName(ByVal strVIN As String)
Dim fldName() As String
fldName = Split(strVIN.ToString, "\",, CompareMethod.Text)
For x = 0 To UBound(fldName) - 1
If InStr(fldName(x), "SCC", CompareMethod.Text) > 0 Then
strVIN = Trim(fldName(x))
If errListBox.Items.Contains(strVIN) = True Then
errListBox.Items.Remove(strVIN)
End If
If VINListBox.Items.Contains(strVIN) = False Then
VINListBox.Items.Add(strVIN)
End If
Exit For
End If
Next
End Sub
Private Sub GetErrVinName(ByVal strVIN As String)
Dim fldName() As String
fldName = Split(strVIN.ToString, "\",, CompareMethod.Text)
For x = 0 To UBound(fldName) - 1
If InStr(fldName(x), "SCC", CompareMethod.Text) > 0 Then
strVIN = Trim(fldName(x))
If VINListBox.Items.Contains(strVIN) = False Then
If errListBox.Items.Contains(strVIN) = False Then
errListBox.Items.Add(strVIN)
Else
Exit Sub
End If
Else
Exit Sub
End If
Exit For
End If
Next
End Sub

Visual Basic - Selecting values from a string and defining them as something

I have a log file in txt, inside are strings of information. one string looks like this:
49000 120614 12334480 12 32 2 90 90 90 321 384 2 345 873 890
each value between the spaces represents something in specific, (e.g the second line "120614" is the date "12 June 2014") I am writing a program where I load the txt file into it, and then when i click a certain button it will take this string and put all the values into a specific text box, for instance, "Date = 12 06 2014". I have been researching how to find a certain line and declare that line with its contents as something, but I have not found the answer!! I am using Visual Basic to write it, and I really need help with what direction to take, will stramreader be able to do this?? What function am I looking for?
Here is my code for loading the file.. Just incase.
Public Class Form1
Private Sub browsebtn1_Click(sender As Object, e As EventArgs) Handles browsebtn1.Click
Dim filedialog As New OpenFileDialog 'openfiledialog1 is now filedialog'
filedialog.Filter = "Text Document|*.txt" 'filter the openfiledialogs file extension to txt only'
filedialog.Title = "Select Bosvark Log File.." 'openfiledialog title'
If filedialog.ShowDialog = Windows.Forms.DialogResult.OK Then 'if the file is chosen then..'
filepath1.Text = filedialog.FileName 'filepath1 text is file path of selected file'
RichTextBox1.LoadFile(filepath1.Text, RichTextBoxStreamType.PlainText) 'richtextbox1 retrieves the file path and displays the document'
End If
End Sub
Private Sub convertbtn_Click(sender As Object, e As EventArgs) Handles convertbtn.Click
If RichTextBox1.Text = "" Then
MessageBox.Show("Please load a file first!") 'If user doesnt load a file, give them an error message.'
End If
End Sub
Private Sub RichTextBox1_TextChanged(sender As Object, e As EventArgs) Handles RichTextBox1.TextChanged
If RichTextBox1.Text = "" Then
RichTextBox1.Visible = False 'If there is no file loaded, The textbox will not appear.'
Else
RichTextBox1.Visible = True 'if the file is loaded, textbox will appear.'
End If
End Sub
End Class
you can load the contents of the file to a string variable (if the file isnt too large)
Dim intFile As Integer
Dim strFile As String
Dim strData As String
intFile = FreeFile
strFile = "c:\temp\file.txt"
Open strFile For Input As #intFile
strData = Input(LOF(intFile), #intFile)
Close #intFile
you can split all the data into an array per line
Dim strLine() As String
strLine = Split(strData)
you can loop over all lines to perform some action on all lines
Dim lngLine As Long
For lngLine = 0 To UBound(strLine)
'do action
Next lngLine
or just perform an action on one specific line:
dim strField() as String
'split line into array separated per spaces
strField = Split(strLine(lngLine), " ")

Counting amount of files chosen

I am using a function to select a few files:
Module OpenFileMod
Public Function OpenFile() As String()
'declare a string, this is will contain the filename that we return
Dim strFileNames As String()
'declare a new open file dialog
Dim fileDialogBox As New OpenFileDialog()
fileDialogBox.Filter = "Excel Files (*.xls)|*.xls"
fileDialogBox.Multiselect = True
'this line tells the file dialog box what folder it should start off in first
'I selected the users my document folder
fileDialogBox.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
'Check to see if the user clicked the open button
If (fileDialogBox.ShowDialog() = DialogResult.OK) Then
strFileNames = fileDialogBox.FileNames
Else
MsgBox("You did not select a file!")
End If
'return the name of the file
Return strFileNames
End Function
End Module
I would like to know how many files the user has chosen.
How can I do that?
fileDialogBox.FileNames is an array, so you can simply check its Length property
or
strFileNames.Length