我几个小时都在苦苦挣扎,我不情愿地发表这个问题。
我被分配制作一个程序,该程序读取名称,将其保存到文本框,并在表单关闭时将名称和编号写入文本文件。在表单加载后,它应该从2个文本文件中读取名称和编号并显示该信息。将自动生成该编号,并从文本文件中读取下一个客户编号。
但是,我在使用streamwriter时遇到了困难:当我尝试写outFile2时,我特别遇到错误:outFile2的NullReferenceError。
基本上outFile2不会打开文件或附加输出文件。如何在不试图找出每个读/写缓冲区方法崩溃的原因的情况下让这个程序工作?
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
答案 0 :(得分:3)
这是问题所在:
outFile1 = IO.File.CreateText("CustomerNumbers.txt")
inFile1 = IO.File.OpenText("CustomerNumbers.txt")
您无法同时在同一文件上打开Reader and Writer。当您尝试时,OpenText
将抛出文件正在使用的IOException
。 但是,因为该代码位于Form_Load
,您可能看不到它;相反,NET放弃并显示形式而不执行事件中的其余代码。这使第二个流对象保留为Nothing
。
稍后当您尝试使用它时,您会得到一个NullReferenceException
,因为它从未创建过。
:一种。关闭并处理您的读者和作者。
将Writer代码移动到其他地方时遇到的问题之一(请参阅注释)是该文件正在使用中(最初在Form_Load中抛出的相同异常,您根本看不到它)。这是因为您的代码在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
不关闭和处理它们 - 只是让它们超出范围 - 可能导致泄漏。
<强> B中。尽量少用范围
由于您不需要Writer直到(或如果!),他们单击“保存”按钮,等待在那里创建它。
如果你应该声明它们,创建它们,使用它们并根据需要处理它们,它们就没有必要具有形式级别的范围:
Public Class frmMain
Private inFile1, inFile2 As IO.StreamReader
Private outFile1, outFile2 As IO.StreamWriter
其中声明变量确定其范围。这些是在表单级别(相对于本地 - 在Sub中)声明的,因此它们在表单中的任何位置都可用。这可能是你的意图,但这是一个不好的做法。
上述两个示例都在本地声明和创建流变量,开展业务,然后关闭并处理它们。 Using
表单更简洁,因为它为您实现了Dim
,Close()
和Dispose()
。
<强>℃。流是流
读者和作者都需要关闭和处理。
简而言之,如果对象支持Dispose
方法,请使用它(在对象浏览器中查看:查看菜单 - &gt;对象浏览器)。
答案 1 :(得分:1)
首先,您以非常错误的方式使用StreamReaders / Writers。您应该使用Using
来实现它们。其次,你在btnSaveCustomer.Click
事件处理程序中获取异常的原因是因为你试图在没有实例化的情况下引用outFile2
;您只将其声明为全局变量。
即使您尝试使用outFile2 = IO.File.CreateText("CustomerNames.txt")
或outFile2 = IO.File.AppendText("CustomerNames.txt")
在Form.Load事件中实例化它,这些实际上可能并不成功。有一个已知问题,可以在Form.Load
事件中吃掉异常。
以下是如何将流读取器/编写器与Using
语句一起使用的示例,它应该执行您发布的代码所做的所有操作。我强烈建议你不要为你的家庭作业项目直接复制/粘贴以下代码。我使用了一些可能超出编程101类范围的东西。
Option Strict On
Public Class frmMain
'Private inFile1, inFile2 As IO.StreamReader
'Private outFile1, outFile2 As IO.StreamWriter
Private CustomerNamesPath As String = "C:\StackOverFlow\CustomerNames.txt"
Private CustomerNumbersPath As String = "C:\StackOverFlow\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