【问题标题】:StreamReader throws System.NullReferenceExceptionStreamReader 抛出 System.NullReferenceException
【发布时间】:2016-08-27 20:45:27
【问题描述】:

我在让一段代码工作时遇到了一些困难。这是叙述:我有多个具有特定格式的文本文件(因为它们是代码生成的),我需要提取特定的文本块并在文本框中仅显示这些文本块。例如,一个这样的块将是“STN COMMENT”“END COMMENT”。该文件可能有两个、三个甚至 10 个这样的块,并且会有不同类型的块,其中 COMMENT 将替换为 QUESTION、ANNOUNCEMENT 或 TRAFFIC。都以相应的“END”结束。这是我尝试的第一个代码段:

'block to parse only this user's announcements
'dl is variable alias for: Environment.NewLine + Environment.NewLine
txtNetLog.Text = "" 'clears the textbox
TmpFileName = logPath + ByCall + "-" + Format(Now, "dd-MMM-yyyy") + ".tmp" 'sets filename with path defined in module
Try
    Using sr As StreamReader = New StreamReader(TmpFileName)
    Dim line As String = sr.ReadLine()
        While Not (line Is Nothing)
            line = sr.ReadLine()
            If line.Contains("STN ANNOUNCEMENT") Then '***This is line 238 from exception
                Do
                    txtNetLog.Text = txtNetLog.Text & line + dl
                    line = sr.ReadLine()
                Loop Until line.Contains("END ANNOUNCEMENT")
             End If
         End While
     End Using
 Catch ex As Exception
     Dim msg As String = "Error: Failure Parsing Temp File For Announcements. Contact Developer" + dl + ex.ToString
     Dim title = "Error in StreamReader"
     Dim errorFile As System.IO.StreamWriter
     Dim errorFileName As String = logPath + "Errors.txt"
     errorFile = My.Computer.FileSystem.OpenTextFileWriter(errorFileName, True)
     errorFile.Write(msg)
     errorFile.Close()
     MsgBox(msg, MsgBoxStyle.ApplicationModal, title)
 End Try

这产生了以下异常:

System.NullReferenceException:对象引用未设置为对象的实例。 在 C:\Users\KE4NHW\Documents\Visual Studio 2010\Projects\GSPASEC Net Control\GSPASEC Net Control\ReviewNetLogFrm.ParseLog(Int32 DataType, Int32 SortType) 中的 GSPASEC_Net_Control.ReviewNetLogFrm.ParseLog(Int32 DataType, Int32 SortType):第 238 行

我在上面的代码中标记了第 238 行。但是,这是该块的输出:

STN 公告:18:50:54 KE4NHW

ASDFASDFASDFASDF

STN 公告:18:50:57 KE4NHW

DFADFADFASWERASDF

STN 公告:18:51:01 KE4NHW

GHSDETGJNHSDFAW34ASDFG

此输出缺少应放入文本框中的“END ANNOUNCEMENT”行,但除此之外它确实获得了所有公告。它错过了每个文本块(结束行)的一行并抛出 nullreferenceexception;除此之外,如果我可以显示结束语句,那么至少我们将拥有所有需要提取的文本。

我也尝试了以下更改但没有成功,都产生相同的错误:

更改了 While Not (line Is Nothing)...End While to Do...循环直到 line Is Nothing

将其更改为 Do until line is nothing...循环

我最新测试的版本是这样的:

    txtNetLog.Text = ""
    'block to parse only this user's Comments
    TmpFileName = logPath + ByCall + "-" + Format(Now, "dd-MMM-yyyy") + ".tmp"
    Try
        Using sr As StreamReader = New StreamReader(TmpFileName)
            Dim line As String = sr.ReadLine()
            Do Until line Is Nothing
                line = sr.ReadLine()
                If line.Contains("STN COMMENT") Then
                    Do Until line.Contains("END COMMENT")
                        txtNetLog.Text = txtNetLog.Text + line + nl + nl
                        line = sr.ReadLine()
                    Loop
                End If
            Loop
        End Using
    Catch ex As Exception
        Dim msg As String = "Error: Failure Parsing Temp File For Comments. Contact Developer" + nl + nl + ex.ToString
        Dim title = "Error in StreamReader"
        MsgBox(msg, MsgBoxStyle.ApplicationModal, title)
        ErrorLogWriter("ErrorLog.txt", msg)
    End Try

同样的事情。不在文本框中输入“END COMMENT”,并引发相同的异常。我没有强制 try 块只是使异常静音的想法,但这肯定会导致问题。对这个有什么想法吗?

【问题讨论】:

  • 在阅读了上一行之后,您并没有检查line 是否为空。
  • 在调试器中单步调试代码会在几分钟内告诉您问题的原因。你应该学会使用它。
  • 您也没有检查读取的第一行 (Dim line ....) 的内容,因此该行表示其中一个块的开始,代码将错过它。如果读取的文件很小,可以将整个文件读入并逐行处理;如果它们很大,您可能应该使用 StringBuilder 作为结果......在调试器上也是如此

标签: vb.net vb.net-2010 streamreader


【解决方案1】:

看看这是否可行:

Dim sb As New StringBuilder
Dim startToken = "STN ANNOUNCEMENT"
Dim endToken = "END ANNOUNCEMENT"
Dim line As String

Using sr As StreamReader = New StreamReader("C:\Temp\LogData.Txt")

    Do Until sr.EndOfStream
        line = sr.ReadLine
        If line.StartsWith(startToken) Then
            sb.AppendLine(line)
            Do Until sr.EndOfStream OrElse line.StartsWith(endToken)
                line = sr.ReadLine
                sb.AppendLine(line)
            Loop
        End If
    Loop

End Using

tbLog.Text = sb.ToString

Sample data used

我不知道格式错误的块的可能性有多大,但我可能会简单地寻找“END”作为endToken,这样任何类型的块的结尾都会停止捕获。它给了它重新同步的机会。

或者块结束信号可以包括任何块的开始。在这种情况下,您可以手动添加“END ANNOUNCEMENT”以保持一致性或其他内容以注意检测到格式错误的块。这些内容可能包括非公告数据。

此外,它使用StringBuilder 而不是无休止地弄乱 UI 控件。字符串是不可变的,因此附加到 Text 属性意味着一遍又一遍地重建它。当捕获的线超过某个点时,这应该会加快速度。

【讨论】:

  • 您在此处提供的解决方案完美运行!我确实必须对其进行一些调整,例如在字符串生成器追加中添加 Environment.NewLine,但除此之外完美无缺!我的声誉还不够高,因为我还不够熟练,无法回答其他人的问题,但如果是这样,我肯定会赞成这个问题。如果其他人可以对此进行投票,请这样做,因为这是一个很好的解决方案。非常感谢 Plutonix 和所有帮助我的人! Grr 文本解析很痛苦。我想了一分钟我将不得不突破或导入正则表达式......
  • 这也有效:Using sr As StreamReader = New StreamReader(TmpFileName) Dim line As String = sr.ReadLine() Do If line.Contains("STN COMMENT") Then Do txtNetLog.Text = txtNetLog.Text + nl + line line = sr.ReadLine() Loop Until line.Contains("END COMMENT") txtNetLog.Text = txtNetLog.Text + nl End If line = sr.ReadLine Loop Until line Is Nothing End Using
  • 对不起,如果我不能使用,我假设您知道在哪里放置换行符;指示他们去哪里。这几乎可以工作,但在可以调整的换行符上有点偏离。似乎整个问题是在 Do...Loop until line Is Nothing 上方有一个 readline() 。它导致 line.Contains(token) 中断,因为它试图解析 Nothing。哇,这都是关于位置的。我需要复习一下程序逻辑...谢谢大家的帮助,它现在可以工作了!!!
  • 不需要使用 StringBuilder 添加 NewLine - 每个 AppendLine 都会为您执行此操作。如果可行,请单击答案旁边的复选标记。它将这个从未回答的列表中移出,帮助其他人找到好的答案并向其他人展示你参与了这个过程。
  • 我们去,那里有复选标记。我添加额外换行符的唯一原因是当文本块显示在用户屏幕上时,可以在它们之间留出更多的喘息空间。使它更容易阅读。既然这是可行的,我可以尝试用富文本框替换标准文本框。主要是文本框只能由程序写入,只能由用户读取。同样的方式我避免了格式错误的块:只有程序才能输入;这样我就可以明确我的开始和结束标记。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-11
  • 1970-01-01
相关资源
最近更新 更多