FileStream Reader和Writer对象麻烦

时间:2015-04-17 19:50:28

标签: vb.net visual-studio-2012 io

我几个小时都在苦苦挣扎,我不情愿地发表这个问题。

我被分配制作一个程序,该程序读取名称,将其保存到文本框,并在表单关闭时将名称和编号写入文本文件。在表单加载后,它应该从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

2 个答案:

答案 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表单更简洁,因为它为您实现了DimClose()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