如何解决“索引超出数组范围”

时间:2019-08-13 01:09:40

标签: arrays vb.net

使用Visual Basic。尝试将一系列报告加载到列表视图时,列表视图每次加载时都会由3列(位置,日期和严重性级别)组成,由于``索引超出数组范围''而崩溃时会崩溃(尤其是在DOI = reportdetails(1)周围)在我的代码中。它正在从文本文件中加载。我在文本文件中有数据,所以我不确定为什么要说我要的信息不存在。该程序还加密文本文件。

Dim locate, DOI, SeverityLevel, ReportTitles, EReportTitles, ReportDetails(2) As String

Dim Index As Integer 'Define Variables
Dim FileNum As Integer = FreeFile()
Dim IncidentReport As ListViewItem

lstReports.Items.Clear()

If Dir("ReportTitles.txt") <> "" Then 'If the directory of the file exits then continue

    FileOpen(FileNum, "ReportTitles.txt", OpenMode.Input) 'open file
    Do Until EOF(FileNum)   'Repeat until the end of the file is reached

        EReportTitles = "" 'Clear variables, to safeguard against crashes or errors

        ReportTitles = ""
        EReportTitles = LineInput(FileNum) 'EReportTitles is equal to the current file line

        Dim FileName As String = "ReportTitles.txt"   'Define variables

        Dim I, C As Integer
        Dim Last As Integer = EReportTitles.Length - 1
        Dim ThisChar As Char
        For I = 0 To Last   'Begin for loop 
            ThisChar = EReportTitles.Chars(I)  'Decryption of file
            C = Asc(ThisChar) Xor 22
            ThisChar = Chr(C)
            ReportTitles += ThisChar
        Next
        If ReportTitles <> "" Then
            ReportDetails = Split(ReportTitles, ",")  'Split the lines when a "," is encountered

            locate = ReportDetails(0) 'Assosciate to relevant value in array

            DOI = ReportDetails(1)
            SeverityLevel = ReportDetails(2)

            IncidentReport = New ListViewItem
            IncidentReport.Text = locate    'Add relevant values to IncidentReport ListViewItem variable
            IncidentReport.SubItems.Add(DOI)
            IncidentReport.SubItems.Add(SeverityLevel)

            lstReports.Items.Add(IncidentReport)  'Transfer IncidentReport to listview
        Else

        End If
    Loop
    FileClose(FileNum)  'close file
End If

预期结果是将所有报告位置,日期和严重性级别加载到列表视图中。

对于这个问题的格式也很抱歉,我是堆栈溢出的新手。

2 个答案:

答案 0 :(得分:2)

像这样声明ReportDetails毫无意义:

ReportDetails(2) As String

因为它创建了一个您永远不会使用的数组。在这里:

ReportDetails = Split(ReportTitles, ",")

无论如何您正在创建一个新数组,该数组的长度将由ReportTitles中的定界符数量确定。如果得知1是该数组的无效索引,则该数组只能包含1个元素,这意味着ReportTitles不包含任何定界符。

这不是我们必须向您解释的内容,因为您可以通过调试轻松地自己看到它,并且应该始终在此处发布之前进行调试。在代码的顶部设置一个断点,一行一行地浏览并检查每一步的状态。您可以轻松查看ReportTitlesReportDetails的内容以及其他任何内容,以查看它们是否符合您的期望。

如果这里的重点是读取CSV文件,那么您确实应该使用TextFieldParser类。该类的文档包括一个代码示例。

答案 1 :(得分:0)

这需要.Net Standard 2.1,因此我不确定VB.Net是否可以对SpanAction方法使用必需的String.Create(),但是如果受支持,它应该大大优于原始方法

lstReports.Items.Clear()

'Read and "Decrypt" (and I use that term loosely) the file with only a single heap allocation
Dim file As String
Using fs As FileStream = File.OpenRead("ReportTitles.txt")
    file = String.Create(fs.Length, fs, 
        Sub(chars, stream)
            For i As Integer = 0 To stream.Length - 1
                'THIS IS NOT ENCRYPTION! At best, it's obfuscation.
                chars(i) = Chr(fs.ReadByte() Xor 22)
            Next
        End Sub)
End Using

'Use an actual CSV parser
Using reader As New StringReader(file), _
      parser As New TextFieldParser(reader)

    parser.TextFieldType = FileIO.FieldType.Delimited
    parser.Delimiters = New String() {","}

    Dim row As String()

    While Not parser.EndOfData
        row = parser.ReadFields()

        If row.Length >= 3 Then
            Dim IncidentReport As New ListViewItem()
            IncidentReport.Text = row(0) '
            IncidentReport.SubItems.Add(row(1))
            IncidentReport.SubItems.Add(row(2))

            lstReports.Items.Add(IncidentReport)  
        End If
    End While
End Using

如果您无法使用该版本,则效果不尽如人意,但仍比原始版本更好:

lstReports.Items.Clear()

'Load and "Decrypt" the file  
Dim file As String
Using fs As FileStream = File.OpenRead("ReportTitles.txt")
    Dim builder As New StringBuilder(fs.Length)
    For i As Integer = 0 To fs.Length - 1
        'THIS IS NOT ENCRYPTION! At best, it's obfuscation.
        builder.Append(Chr(fs.ReadByte() Xor 22))
    Next
    file = builder.ToString()
End Using

'Use an actual CSV parser
Using reader As New StringReader(file), _
      parser As New TextFieldParser(reader)

    parser.TextFieldType = FileIO.FieldType.Delimited
    parser.Delimiters = New String() {","}

    Dim row As String()

    While Not parser.EndOfData
        row = parser.ReadFields()

        If row.Length >= 3 Then
            Dim IncidentReport As New ListViewItem()
            IncidentReport.Text = row(0) '
            IncidentReport.SubItems.Add(row(1))
            IncidentReport.SubItems.Add(row(2))

            lstReports.Items.Add(IncidentReport)  
        End If
    End While
End Using

在两种情况下,请使用Try/Catch而不是Dir()来检查位置是否存在。只需尝试打开文件。 Dir()花费了额外的磁盘搜寻费用,并且编程中几乎没有什么事情比磁盘I / O慢。