FileStream Reader 和 Writer 对象问题
FileStream Reader and Writer Objects Trouble
我已经纠结了几个小时了,我post这个问题很不情愿。
我被指派制作一个程序,该程序读取姓名,将其保存到文本框,并在表格关闭时将姓名和号码写入文本文件。加载表单后,它应该从 2 个文本文件中读取名称和编号并显示该信息。该号码是自动生成的,下一个客户号码是从文本文件中读取的。
但是,我在使用 streamwriter 时遇到了困难:当我尝试写入 outFile2 时特别遇到错误:outFile2 的 NullReferenceError。
基本上 outFile2 不会打开文件或附加输出文件。我怎样才能让这个程序工作而不试图弄清楚为什么 read/write 缓冲区的每个方法都会在我身上崩溃?
Private inFile1, inFile2 As IO.StreamReader
Private outFile1, outFile2 As IO.StreamWriter
Private customerNum As Integer = 1
Private customerName As String
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim tempStr As String
If IO.File.Exists("CustomerNumbers.txt") = False Then
outFile1 = IO.File.CreateText("CustomerNumbers.txt")
inFile1 = IO.File.OpenText("CustomerNumbers.txt")
Else
inFile1 = IO.File.OpenText("CustomerNumbers.txt")
outFile1 = IO.File.AppendText("CustomerNumbers.txt")
End If
If IO.File.Exists("CustomerNames.txt") = False Then
outFile2 = IO.File.CreateText("CustomerNames.txt")
inFile2 = IO.File.OpenText("CustomerNames.txt")
Else
inFile2 = IO.File.OpenText("CustomerNames.txt")
outFile2 = IO.File.AppendText("CustomerNames.txt")
End If
If inFile1.Read = Nothing Then
customerNum = 1
txtList.Text = customerNum
End If
Do While inFile1.Peek() <> -1
tempStr = inFile1.ReadLine
customerNum = tempStr
Loop
Do While inFile2.Peek() <> -1
customerName = inFile2.ReadLine().ToString
txtList.Text += customerName & vbCrLf
Loop
lblNumber.Text = customerNum
inFile1.Close()
inFile2.Close()
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
outFile1.WriteLine(customerNum)
outFile1.Close()
outFile2.Close()
Me.Close()
End Sub
Private Sub btnSaveCustomer_Click(sender As Object, e As EventArgs) Handles btnSaveCustomer.Click
If (txtCustomerName.Text <> Nothing) Then
txtList.Text += customerNum & " " & txtCustomerName.Text & vbCrLf
//error thrown here usually
outFile2.WriteLine(customerNum.ToString & " " & txtCustomerName.Text.ToString)
customerNum = customerNum + 1
lblNumber.Text = customerNum
txtCustomerName.Clear()
txtCustomerName.Focus()
End If
End Sub
粘贴自评论:
If IO.File.Exists("CustomerNames.txt") = False Then
Dim outFile1, outFile2 As IO.StreamWriter
outFile2 = IO.File.CreateText("CustomerNames.txt")
Using outFile2 = IO.File.AppendText("CustomerNames.txt")
outFile2.WriteLine(customerNum.ToString & " " & txtCustomerName.Text.ToString)
End Using
End I
这是问题所在:
outFile1 = IO.File.CreateText("CustomerNumbers.txt")
inFile1 = IO.File.OpenText("CustomerNumbers.txt")
您不能在同一个文件上同时打开 Reader 和 Writer。当您尝试时,OpenText
会抛出一个 IOException
文件正在使用中。 但是 因为该代码在 Form_Load
中,您可能看不到它;相反,NET 放弃并显示形式 而没有执行事件 中的其余代码。这将第二个流对象保留为 Nothing
.
稍后当您尝试使用它时,您会得到一个 NullReferenceException
,因为它从未被创建过。
补救措施
一个。关闭并处理你的 reader 和 writer。
将 Writer 代码移动到其他地方时遇到的问题之一(请参阅评论)是文件正在使用中(最初在 Form_Load 中抛出的相同异常,您只是看不到它)。这是因为您的代码使 reader 在 Form_Load 中处于打开状态。正确:
Dim infil As StreamReader = IO.File.OpenText("CustomerNames.txt")
customerName = infil.ReadLine()
infil.Close() ' close the stream
infil.Dispose() ' dispose of it
这些可以使用 Using
块来缩短,这些块将在本地块中为您声明、关闭和处理事物:
' declare outF and open it in one line
Using outFile As StreamWriter = File.CreateText("CustomerNames.txt")
'... write
End Using ' close and dispose of stream
不关闭和处理它们 - 只是让它们超出范围 - 会导致泄漏。
乙。使用尽可能小的范围
由于在(或如果!)他们单击“保存”按钮之前您不需要 Writer,请等待在那里创建它。
如果您应该声明它们、创建它们、使用它们并根据需要处置它们,则它们不需要具有表单级范围:
Public Class frmMain
Private inFile1, inFile2 As IO.StreamReader
Private outFile1, outFile2 As IO.StreamWriter
在哪里 你声明一个变量决定了它的作用域。这些是在表单级别声明的(相对于本地 - 在 Sub 内部),因此它们在表单中的任何地方都可用。这可能是您想要的,但这是一种不好的做法。
以上两个示例都在本地声明和创建流变量,处理它们的业务,然后关闭并处理它们。 Using
形式更简洁,因为它为您实现了 Dim
、Close()
和 Dispose()
。
C。流就是流
Readers 和 Writers 都需要关闭和处理。
简而言之,如果对象支持 Dispose
方法,请使用它(在对象浏览器中查看:查看菜单 -> 对象浏览器)。
首先,您使用 StreamReaders/Writers 的方式非常错误。您应该使用 Using
来实现它们。其次,您在 btnSaveCustomer.Click
事件处理程序中出现异常的原因是因为您试图引用 outFile2
而不实例化它;您只是将其声明为全局变量。
即使您尝试在 Form.Load 事件中用 outFile2 = IO.File.CreateText("CustomerNames.txt")
或 outFile2 = IO.File.AppendText("CustomerNames.txt")
实例化它,这些可能实际上并没有成功。存在一个已知问题,即 Form.Load
事件中的异常可能被吃掉。
这是一个如何将 streamreader/writers 与 Using
语句一起使用的示例,它应该可以执行您发布的代码所做的所有操作。我强烈建议您不要直接 copy/paste 为您的作业项目提交以下代码。我使用了几个可能超出编程范围的东西 101 class.
Option Strict On
Public Class frmMain
'Private inFile1, inFile2 As IO.StreamReader
'Private outFile1, outFile2 As IO.StreamWriter
Private CustomerNamesPath As String = "C:\Whosebug\CustomerNames.txt"
Private CustomerNumbersPath As String = "C:\Whosebug\CustomerNumbers.txt"
Private CustomerNamesContents As New List(Of String)
Private CustomerNumbersContents As New List(Of String)
Private customerNum As Integer = 1
Private customerName As String
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
Using numbersSR As New IO.StreamReader(IO.File.Open(CustomerNumbersPath, IO.FileMode.OpenOrCreate, IO.FileAccess.Read))
Do While Not numbersSR.EndOfStream
CustomerNumbersContents.Add(numbersSR.ReadLine)
Loop
End Using
Using namesSR As New IO.StreamReader(IO.File.Open(CustomerNamesPath, IO.FileMode.OpenOrCreate, IO.FileAccess.Read))
Do While Not namesSR.EndOfStream
CustomerNamesContents.Add(namesSR.ReadLine)
Loop
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
'If inFile1.Read = Nothing Then
' customerNum = 1
' txtList.Text = customerNum
'End If
If CustomerNumbersContents.Count = 0 Then
customerNum = 1
txtList.Text = CStr(customerNum)
End If
'Do While inFile1.Peek() <> -1
' tempStr = inFile1.ReadLine
' customerNum = tempStr
'Loop
CustomerNumbersContents.ForEach(Sub(x) customerNum = CInt(x))
'Do While inFile2.Peek() <> -1
' customerName = inFile2.ReadLine().ToString
' txtList.Text += customerName & vbCrLf
'Loop
CustomerNamesContents.ForEach(Sub(x) txtList.Text &= x & vbCrLf)
lblNumber.Text = CStr(customerNum)
'inFile1.Close()
'inFile2.Close()
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Try
Using numbersSR As New IO.StreamWriter(IO.File.Open(CustomerNumbersPath, IO.FileMode.Create, IO.FileAccess.Write))
CustomerNumbersContents.ForEach(Sub(x) numbersSR.WriteLine(x))
End Using
Using namesSR As New IO.StreamWriter(IO.File.Open(CustomerNamesPath, IO.FileMode.Create, IO.FileAccess.Write))
CustomerNamesContents.ForEach(Sub(x) namesSR.WriteLine(x))
End Using
Catch ex As Exception
MsgBox(ex.Message)
Finally
Me.Close()
End Try
End Sub
Private Sub btnSaveCustomer_Click(sender As Object, e As EventArgs) Handles btnSaveCustomer.Click
If (txtCustomerName.Text <> Nothing) Then
txtList.Text += customerNum & " " & txtCustomerName.Text & vbCrLf
CustomerNamesContents.Add(customerNum.ToString & " " & txtCustomerName.Text.ToString)
CustomerNumbersContents.Add(CStr(customerNum))
customerNum = customerNum + 1
lblNumber.Text = CStr(customerNum)
txtCustomerName.Clear()
txtCustomerName.Focus()
End If
End Sub
End Class
我已经纠结了几个小时了,我post这个问题很不情愿。
我被指派制作一个程序,该程序读取姓名,将其保存到文本框,并在表格关闭时将姓名和号码写入文本文件。加载表单后,它应该从 2 个文本文件中读取名称和编号并显示该信息。该号码是自动生成的,下一个客户号码是从文本文件中读取的。
但是,我在使用 streamwriter 时遇到了困难:当我尝试写入 outFile2 时特别遇到错误:outFile2 的 NullReferenceError。
基本上 outFile2 不会打开文件或附加输出文件。我怎样才能让这个程序工作而不试图弄清楚为什么 read/write 缓冲区的每个方法都会在我身上崩溃?
Private inFile1, inFile2 As IO.StreamReader
Private outFile1, outFile2 As IO.StreamWriter
Private customerNum As Integer = 1
Private customerName As String
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim tempStr As String
If IO.File.Exists("CustomerNumbers.txt") = False Then
outFile1 = IO.File.CreateText("CustomerNumbers.txt")
inFile1 = IO.File.OpenText("CustomerNumbers.txt")
Else
inFile1 = IO.File.OpenText("CustomerNumbers.txt")
outFile1 = IO.File.AppendText("CustomerNumbers.txt")
End If
If IO.File.Exists("CustomerNames.txt") = False Then
outFile2 = IO.File.CreateText("CustomerNames.txt")
inFile2 = IO.File.OpenText("CustomerNames.txt")
Else
inFile2 = IO.File.OpenText("CustomerNames.txt")
outFile2 = IO.File.AppendText("CustomerNames.txt")
End If
If inFile1.Read = Nothing Then
customerNum = 1
txtList.Text = customerNum
End If
Do While inFile1.Peek() <> -1
tempStr = inFile1.ReadLine
customerNum = tempStr
Loop
Do While inFile2.Peek() <> -1
customerName = inFile2.ReadLine().ToString
txtList.Text += customerName & vbCrLf
Loop
lblNumber.Text = customerNum
inFile1.Close()
inFile2.Close()
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
outFile1.WriteLine(customerNum)
outFile1.Close()
outFile2.Close()
Me.Close()
End Sub
Private Sub btnSaveCustomer_Click(sender As Object, e As EventArgs) Handles btnSaveCustomer.Click
If (txtCustomerName.Text <> Nothing) Then
txtList.Text += customerNum & " " & txtCustomerName.Text & vbCrLf
//error thrown here usually
outFile2.WriteLine(customerNum.ToString & " " & txtCustomerName.Text.ToString)
customerNum = customerNum + 1
lblNumber.Text = customerNum
txtCustomerName.Clear()
txtCustomerName.Focus()
End If
End Sub
粘贴自评论:
If IO.File.Exists("CustomerNames.txt") = False Then
Dim outFile1, outFile2 As IO.StreamWriter
outFile2 = IO.File.CreateText("CustomerNames.txt")
Using outFile2 = IO.File.AppendText("CustomerNames.txt")
outFile2.WriteLine(customerNum.ToString & " " & txtCustomerName.Text.ToString)
End Using
End I
这是问题所在:
outFile1 = IO.File.CreateText("CustomerNumbers.txt")
inFile1 = IO.File.OpenText("CustomerNumbers.txt")
您不能在同一个文件上同时打开 Reader 和 Writer。当您尝试时,OpenText
会抛出一个 IOException
文件正在使用中。 但是 因为该代码在 Form_Load
中,您可能看不到它;相反,NET 放弃并显示形式 而没有执行事件 中的其余代码。这将第二个流对象保留为 Nothing
.
稍后当您尝试使用它时,您会得到一个 NullReferenceException
,因为它从未被创建过。
补救措施
一个。关闭并处理你的 reader 和 writer。
将 Writer 代码移动到其他地方时遇到的问题之一(请参阅评论)是文件正在使用中(最初在 Form_Load 中抛出的相同异常,您只是看不到它)。这是因为您的代码使 reader 在 Form_Load 中处于打开状态。正确:
Dim infil As StreamReader = IO.File.OpenText("CustomerNames.txt")
customerName = infil.ReadLine()
infil.Close() ' close the stream
infil.Dispose() ' dispose of it
这些可以使用 Using
块来缩短,这些块将在本地块中为您声明、关闭和处理事物:
' declare outF and open it in one line
Using outFile As StreamWriter = File.CreateText("CustomerNames.txt")
'... write
End Using ' close and dispose of stream
不关闭和处理它们 - 只是让它们超出范围 - 会导致泄漏。
乙。使用尽可能小的范围
由于在(或如果!)他们单击“保存”按钮之前您不需要 Writer,请等待在那里创建它。
如果您应该声明它们、创建它们、使用它们并根据需要处置它们,则它们不需要具有表单级范围:
Public Class frmMain
Private inFile1, inFile2 As IO.StreamReader
Private outFile1, outFile2 As IO.StreamWriter
在哪里 你声明一个变量决定了它的作用域。这些是在表单级别声明的(相对于本地 - 在 Sub 内部),因此它们在表单中的任何地方都可用。这可能是您想要的,但这是一种不好的做法。
以上两个示例都在本地声明和创建流变量,处理它们的业务,然后关闭并处理它们。 Using
形式更简洁,因为它为您实现了 Dim
、Close()
和 Dispose()
。
C。流就是流
Readers 和 Writers 都需要关闭和处理。
简而言之,如果对象支持 Dispose
方法,请使用它(在对象浏览器中查看:查看菜单 -> 对象浏览器)。
首先,您使用 StreamReaders/Writers 的方式非常错误。您应该使用 Using
来实现它们。其次,您在 btnSaveCustomer.Click
事件处理程序中出现异常的原因是因为您试图引用 outFile2
而不实例化它;您只是将其声明为全局变量。
即使您尝试在 Form.Load 事件中用 outFile2 = IO.File.CreateText("CustomerNames.txt")
或 outFile2 = IO.File.AppendText("CustomerNames.txt")
实例化它,这些可能实际上并没有成功。存在一个已知问题,即 Form.Load
事件中的异常可能被吃掉。
这是一个如何将 streamreader/writers 与 Using
语句一起使用的示例,它应该可以执行您发布的代码所做的所有操作。我强烈建议您不要直接 copy/paste 为您的作业项目提交以下代码。我使用了几个可能超出编程范围的东西 101 class.
Option Strict On
Public Class frmMain
'Private inFile1, inFile2 As IO.StreamReader
'Private outFile1, outFile2 As IO.StreamWriter
Private CustomerNamesPath As String = "C:\Whosebug\CustomerNames.txt"
Private CustomerNumbersPath As String = "C:\Whosebug\CustomerNumbers.txt"
Private CustomerNamesContents As New List(Of String)
Private CustomerNumbersContents As New List(Of String)
Private customerNum As Integer = 1
Private customerName As String
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
Using numbersSR As New IO.StreamReader(IO.File.Open(CustomerNumbersPath, IO.FileMode.OpenOrCreate, IO.FileAccess.Read))
Do While Not numbersSR.EndOfStream
CustomerNumbersContents.Add(numbersSR.ReadLine)
Loop
End Using
Using namesSR As New IO.StreamReader(IO.File.Open(CustomerNamesPath, IO.FileMode.OpenOrCreate, IO.FileAccess.Read))
Do While Not namesSR.EndOfStream
CustomerNamesContents.Add(namesSR.ReadLine)
Loop
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
'If inFile1.Read = Nothing Then
' customerNum = 1
' txtList.Text = customerNum
'End If
If CustomerNumbersContents.Count = 0 Then
customerNum = 1
txtList.Text = CStr(customerNum)
End If
'Do While inFile1.Peek() <> -1
' tempStr = inFile1.ReadLine
' customerNum = tempStr
'Loop
CustomerNumbersContents.ForEach(Sub(x) customerNum = CInt(x))
'Do While inFile2.Peek() <> -1
' customerName = inFile2.ReadLine().ToString
' txtList.Text += customerName & vbCrLf
'Loop
CustomerNamesContents.ForEach(Sub(x) txtList.Text &= x & vbCrLf)
lblNumber.Text = CStr(customerNum)
'inFile1.Close()
'inFile2.Close()
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Try
Using numbersSR As New IO.StreamWriter(IO.File.Open(CustomerNumbersPath, IO.FileMode.Create, IO.FileAccess.Write))
CustomerNumbersContents.ForEach(Sub(x) numbersSR.WriteLine(x))
End Using
Using namesSR As New IO.StreamWriter(IO.File.Open(CustomerNamesPath, IO.FileMode.Create, IO.FileAccess.Write))
CustomerNamesContents.ForEach(Sub(x) namesSR.WriteLine(x))
End Using
Catch ex As Exception
MsgBox(ex.Message)
Finally
Me.Close()
End Try
End Sub
Private Sub btnSaveCustomer_Click(sender As Object, e As EventArgs) Handles btnSaveCustomer.Click
If (txtCustomerName.Text <> Nothing) Then
txtList.Text += customerNum & " " & txtCustomerName.Text & vbCrLf
CustomerNamesContents.Add(customerNum.ToString & " " & txtCustomerName.Text.ToString)
CustomerNumbersContents.Add(CStr(customerNum))
customerNum = customerNum + 1
lblNumber.Text = CStr(customerNum)
txtCustomerName.Clear()
txtCustomerName.Focus()
End If
End Sub
End Class