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 形式更简洁,因为它为您实现了 DimClose()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