VB.NET - Errors using a StreamReader to read from a text file

I have an Windows Form application that will fill in a text file with entries posted to it.
When the user clicks submit it will ask them to scan their badge. The badge reader uses RFID and will just read the badge number and simulate an Enter key.
On the Enter key it reads a text file containing the Analysts badge numbers, if it finds the badge it writes the text in the application to a text file. This works fine.
If it doesnt find the badge number it asks if they want to add their details. If they click yes it opens another form to enter their name and scan their badge.
It's at this point it goes wrong
Private Sub TxtAnalyst_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtAnalyst.KeyDown
        If e.KeyData = Keys.Return Then
            Using reader As New StreamReader("\\server\AssetPCSoftware\badge numbers.txt")
                While Not reader.EndOfStream
                    Dim line As String = reader.ReadLine()
                    If line.Contains(txtAnalyst.Text) Then
                        Dim analyst As String = line.Split("-"c)(1)
                        Dim sendtext As New StreamWriter("\\server\\Asset Management\Automated_Asset.txt", True)
                        sendtext.WriteLine(DateTime.Now.ToString("dd-MM-yyyy HH:MM"))
                        sendtext.WriteLine(Form1.txtPCno.Text)
                        sendtext.WriteLine(Form1.txtServiceTag.Text)
                        sendtext.WriteLine(Form1.txtModelShipped.Text)
                        If Form1.ComboBox1.SelectedItem <> "" Then
                            Dim cbtext1 As String = Form1.ComboBox1.SelectedItem.ToString()
                            sendtext.WriteLine(cbtext1)
                        End If
                        If Form1.ComboBox2.SelectedItem <> "" Then
                            Dim cbtext2 As String = Form1.ComboBox2.SelectedItem.ToString()
                            sendtext.WriteLine(cbtext2)
                        End If

                        If Form1.txtRetainReason.Text > "" Then
                            sendtext.WriteLine(Form1.txtRetainReason.Text)
                        End If
                        If Form1.txtRetainName.Text > "" Then
                            sendtext.WriteLine(Form1.txtRetainName.Text)
                        End If
                        If Form1.txtOutName.Text > "" Then
                            sendtext.WriteLine(Form1.txtOutName.Text)
                        End If
                        sendtext.WriteLine(analyst)
                        sendtext.Close()
                        'reader.Close()
                    Else
                        '
                        Dim result = MessageBox.Show("Analyst badge number not found, do you want to add your details?", "Badge number not found", MessageBoxButtons.YesNo)
                        If result = Windows.Forms.DialogResult.Yes Then
                            reader.Close()
                            Dim scan As New Add_Badge
                            scan.Show()
                            Me.Close()
                        End If

                    End If
                    'reader.Close()
                End While

            End Using

        End If
    End Sub

Open in new window

The error received is on the line "While Not reader.EndOfStream"
System.ObjectDisposedException was unhandled
  HResult=-2146232798
  Message=Cannot read from a closed TextReader.
  ObjectName=""
  Source=mscorlib
  StackTrace:
       at System.IO.__Error.ReaderClosed()
       at System.IO.StreamReader.get_EndOfStream()
       at Asset_Management.Scan_Badge.TxtAnalyst_KeyDown(Object sender, KeyEventArgs e) in H:\Visual Studio Projects\Asset Management\Asset Management\Scan Badge.vb:line 8
       at System.Windows.Forms.Control.OnKeyDown(KeyEventArgs e)
       at System.Windows.Forms.Control.ProcessKeyEventArgs(Message& m)
       at System.Windows.Forms.Control.ProcessKeyMessage(Message& m)
       at System.Windows.Forms.Control.WmKeyChar(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.TextBoxBase.WndProc(Message& m)
       at System.Windows.Forms.TextBox.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.RunDialog(Form form)
       at System.Windows.Forms.Form.ShowDialog(IWin32Window owner)
       at System.Windows.Forms.Form.ShowDialog()
       at Asset_Management.Form1.btnSubmit_Click(Object sender, EventArgs e) in H:\Visual Studio Projects\Asset Management\Asset Management\Form1.vb:line 69
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at Asset_Management.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

Open in new window

Any ideas? Is this the best way to read the text file?
LVL 2
fruitloopyAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Kyle AbrahamsSenior .Net DeveloperCommented:
try adding an break / exit while after the Me.Close()

I believe the reader is not at the end of stream (even though it's closed) . . . causing your issue.
0
ChloesDadCommented:
You shouldn't close the reader while you are in a loop based on the reader.

It would be better to add a Boolean eg StopLoop that is initialised as false, and set it to true instead of closing the reader, then add the reader.close outside the loop. Change the While to

While Not (reader.EndOfStream OR StopLoop)
0
fruitloopyAuthor Commented:
I tried Kyle's suggestion but it didnt work and it did exit the While and allowed me to enter new badge details. Both badge details and data was saved to their respective text files.
However when I gave it a listed badge number it failed to find it.
 I attempted ChloesDad suggestion but perhaps I'm not implementing it properly?
Private Sub TxtAnalyst_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtAnalyst.KeyDown
        If e.KeyData = Keys.Return Then

Dim StopLoop As Boolean = False

            Using reader As New StreamReader("\\server\AssetPCSoftware\badge numbers.txt")
                While Not (reader.EndOfStream Or StopLoop.Equals(True))
                    Dim line As String = reader.ReadLine()
                    If line.Contains(txtAnalyst.Text) Then
                        Dim analyst As String = line.Split("-"c)(1)
                        Dim sendtext As New StreamWriter("\\server\\Asset Management\Automated_Asset.txt", True)
                        sendtext.WriteLine(DateTime.Now.ToString("dd-MM-yyyy HH:MM"))
                        sendtext.WriteLine(Form1.txtPCno.Text)
                        sendtext.WriteLine(Form1.txtServiceTag.Text)
                        sendtext.WriteLine(Form1.txtModelShipped.Text)
                        If Form1.ComboBox1.SelectedItem <> "" Then
                            Dim cbtext1 As String = Form1.ComboBox1.SelectedItem.ToString()
                            sendtext.WriteLine(cbtext1)
                        End If
                        If Form1.ComboBox2.SelectedItem <> "" Then
                            Dim cbtext2 As String = Form1.ComboBox2.SelectedItem.ToString()
                            sendtext.WriteLine(cbtext2)
                        End If

                        If Form1.txtRetainReason.Text > "" Then
                            sendtext.WriteLine(Form1.txtRetainReason.Text)
                        End If
                        If Form1.txtRetainName.Text > "" Then
                            sendtext.WriteLine(Form1.txtRetainName.Text)
                        End If
                        If Form1.txtOutName.Text > "" Then
                            sendtext.WriteLine(Form1.txtOutName.Text)
                        End If
                        sendtext.WriteLine(analyst)
                        sendtext.Close()
                        'reader.Close()
                    Else
                        '
                        Dim result = MessageBox.Show("Analyst badge number not found, do you want to add your details?", "Badge number not found", MessageBoxButtons.YesNo)
StopLoop.Equals(True)
                        If result = Windows.Forms.DialogResult.Yes Then
                            reader.Close()
                            Dim scan As New Add_Badge
                            scan.Show()
                            Me.Close()
                        End If

                    End If
                    'reader.Close()
                End While

            End Using

        End If
    End Sub

Open in new window

Am I putting it in the wrong place? Is there another way to search the badge text file without a loop?
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

Athar SyedCommented:
Move the entry Add_Badge form outside of the Else section. Just set a flag bAddBadge = False in the If section and bAddBadge = True in the Else section. After the End Using of the reader, check the boolean of bAddBadge and open up the Add_Badge form if it is True.

Even if you do not close the Reader in the else and call the Add_Badge, you might not have enough permission to write to it, as the file is already open and in use by this KeyDown event. Below is a snippet to work your way through.

All this is fine, in a single node environment. In case there are more than one counters scanning the IDs, then you will need to synchronize the write part.

Private Sub CheckBadge(BadgeData As String)
	Dim _bAddBadge As Boolean = False
	' open file for reading only and allow others to be able to write
	Using _stream As Stream = New FileStream("badgefilename", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
		Using _reader As StreamReader = New StreamReader(_stream)
			While Not _reader.EndOfStream
				' code to check if badge exists in file
				Dim _lineData As String = _reader.ReadLine()
				If _lineData.Contains(BadgeData) Then
					_bAddBadge = False
					' Analyse the badge data
				Else
					_bAddBadge = True
				End If
			End While
			_reader.Close()
		End Using
		_stream.Close()
	End Using

	If _bAddBadge Then
		' Open Add_Badge here
	End If
End Sub

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sarabandeCommented:
 If result = Windows.Forms.DialogResult.Yes Then
        reader.Close()
here you close the 'reader' but continue to read from 'reader' at next cycle of the while loop.

you either have to break from while loop what makes it difficult to read and process the 'rest' of input lines.

or, you let the reader open, show the dialog and 'add' badge data (still in while loop) and continue with next input line after that.

i think the second alternative is the best way to handle the case.

Sara
0
fruitloopyAuthor Commented:
Thanks athar13, this is starting to make sense. It's almost working but when I run the code and enter a badge number that DOES exist it still shows the message "Analyst badge number not found, do you want to add your details?". If I click No it adds all the details including the matched analysts badge name corresponding to the badge number.
Private Sub TxtAnalyst_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtAnalyst.KeyDown
        If e.KeyData = Keys.Return Then
            Dim _bAddBadge As Boolean = False
            Using _stream As Stream = New FileStream("\\server\Asset Management\AssetPCSoftware\badge numbers.txt", FileMode.Open, FileAccess.ReadWrite)
                Using _reader As StreamReader = New StreamReader(_stream)
                    While Not _reader.EndOfStream
                        Dim _lineData As String = _reader.ReadLine()
                        If _lineData.Contains(txtAnalyst.Text) Then
                            _bAddBadge = False
                            Dim analyst As String = _lineData.Split("-"c)(1)
                            Dim sendtext As New StreamWriter("\\server\Asset Management\Automated_Asset.txt", True)
                            sendtext.WriteLine(DateTime.Now.ToString("dd-MM-yyyy HH:MM"))
                            sendtext.WriteLine(Form1.txtPCno.Text)
                            sendtext.WriteLine(Form1.txtServiceTag.Text)
                            sendtext.WriteLine(Form1.txtModelShipped.Text)
                            If Form1.ComboBox1.SelectedItem <> "" Then
                                Dim cbtext1 As String = Form1.ComboBox1.SelectedItem.ToString()
                                sendtext.WriteLine(cbtext1)
                            End If
                            If Form1.ComboBox2.SelectedItem <> "" Then
                                Dim cbtext2 As String = Form1.ComboBox2.SelectedItem.ToString()
                                sendtext.WriteLine(cbtext2)
                            End If

                            If Form1.txtRetainReason.Text > "" Then
                                sendtext.WriteLine(Form1.txtRetainReason.Text)
                            End If
                            If Form1.txtRetainName.Text > "" Then
                                sendtext.WriteLine(Form1.txtRetainName.Text)
                            End If
                            If Form1.txtOutName.Text > "" Then
                                sendtext.WriteLine(Form1.txtOutName.Text)
                            End If
                            sendtext.WriteLine(analyst)
                            sendtext.Close()
                        Else
                            _bAddBadge = True


                        End If

                    End While
                    _reader.Close()

                End Using
                _stream.Close()
            End Using
            If _bAddBadge Then
                Dim result = MessageBox.Show("Analyst badge number not found, do you want to add your details?", "Badge number not found", MessageBoxButtons.YesNo)
                If result = Windows.Forms.DialogResult.Yes Then
                    Dim scan As New Add_Badge
                    scan.Show()
                    Me.Close()


                End If
            End If

        End If
    End Sub

Open in new window

0
Athar SyedCommented:
The below snippet failed on me!!!
Public Sub ContainsDemo()
  Dim _whattoCheck As String = "abc1234"
  Dim _whereToCheck As String = "ABC1234-Bob The Builder"

  If _whereToCheck.Contains(_whattoCheck) Then
    Dim _who As String = _whereToCheck.Split("-"c)(1)
    MsgBox(String.Format("Hello {0}", _who))
  Else
    MsgBox("Identify yourself you fiend intruder!!!")
  End If
End Sub

Open in new window


That's because the _what & _where are in different cases. Maybe same is your case. Try making both same case
If _lineData.ToLower().Contains(txtAnalyst.Text.ToLower()) Then

Open in new window


This might be why, it is asking to Add as a new Badge even though it does exist. And when you say no, it is not saving it, but you might be seeing existing data and not newly saved data.
0
fruitloopyAuthor Commented:
Fixed it!
I changed the line
Dim _lineData As String = _reader.ReadLine()
To
Dim _lineData As String = _reader.ReadToEnd()
And it now seems to work correctly
0
fruitloopyAuthor Commented:
Thanks
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.