VB.NET 与文本文件相关的索引超出范围异常

VB.NET Index out of Range exception related to text file

我有一些代码我用了很多次,对我来说一直很管用。然而,最新的使用在某些我似乎无法解决的情况下抛出异常。这是:

我从一个文本文件读取到一个数组,将它用作我的一些控件的绑定源(它根据单个控件的选择自动填充 3 个控件)。我创建了一个具有 4 个属性(名称、ID、DOB 和 DOE)的 Student class。这是我使用的代码:

Private Sub autoFill()
        Dim rost As String = "Roster.txt"
        Dim lines As List(Of String) = File.ReadAllLines(rost).ToList
        Dim list As List(Of Student) = New List(Of Student)
        For i As Integer = 0 To lines.Count - 1
            Dim data As String() = lines(i).Split(":")
            list.Add(New Student() With {
                     .StudentName = data(0),
                     .StudentID = data(1),
                     .StudentDOB = data(2),
                     .StudentDOE = data(3)
                                        })
        Next
        StudentBindingSource.DataSource = list


    End Sub

问题来了。在“For”循环中,当我将 i 设置为 0 到 lines.count -1 时,它会抛出此错误:

VB>NET EXCEPTION

但是...如果我将 i 更改为 1 而不是 0 它会起作用,或者如果我拿走 data(2) 和 data(3) 它会在 i = 0 时起作用。我宁愿使用 0 这样我可以在组合框中有一个空行或“--选择--”等。我认为唯一可能有用的是文本文件中的第一行没有要拆分的内容。这是文本文件的行格式:

Student Name         ID#        DOB          DOE      <-----This header row is NOT in the text file
Last Name, First Name : 0000000 : 01/01/2021 : 01/01/2021

我假设我在这里遗漏了一些非常简单的东西。任何指导将不胜感激!谢谢。

在解决实际问题之前,让我们重新做一些事情。

一种更好的结构代码方法,尤其是在处理数据加载时,是使用一种接受输入并 returns 结果的方法。此外,调用 ToList()ToArray() 是一项 非常昂贵 的性能操作。通常,您可以通过尽可能长时间地使用较低级别 IEnumerable 来显着 提高性能。

考虑到这些原则,请考虑以下代码:

Private Function ReadStudentData(fileName As String) As IEnumerable(Of Student)
    Dim lines As IEnumerable(Of String) = File.ReadLines(fileName)

    Return lines.
        Select(Function(line) line.Split(":")).
        Select(Function(data)
            Return New Student() With {
                .StudentName = data(0),
                .StudentID = data(1),
                .StudentDOB = data(2),
                .StudentDOE = data(3)
            }
        End Function)
End Function

Private Sub autoFill()
    StudentBindingSource.DataSource = ReadStudentData("Roster.txt")
End Sub

现在进入实际问题。问题是 而不是 循环遍历 list 变量。问题是 data 数组。在某些时候,您的一行没有足够的元素。这很常见,例如,作为文件中的最后一行。

许多 方法可以解决这个问题。在某些情况下,异常已经是合适的结果,因为如果你有坏数据,你真的不想继续。在其他情况下,您希望记录错误记录,也许是一份您以后可以轻松查看的报告。或者您可能只想忽略该错误,或​​预过滤具有正确列数的行。这是最后一个选项的示例:

Private Function ReadStudentData(fileName As String) As IEnumerable(Of Student)
    Return File.ReadLines(fileName).
        Select(Function(line) line.Split(":")).
        Where(Function(data) data.Length = 4).
        Select(Function(data) 
            Return New Student() With {
                .StudentName = data(0),
                .StudentID = data(1),
                .StudentDOB = data(2),
                .StudentDOE = data(3)
            }
        End Function)
End Function

Private Sub autoFill()
    StudentBindingSource.DataSource = ReadStudentData("Roster.txt")
End Sub

问题是您没有检查 'data' 是否有足够的元素来创建 'Student'。一个简单的检查应该可以解决它。

Private Sub autoFill()
    Dim rost As String = "Roster.txt"
    Dim lines As List(Of String) = File.ReadAllLines(rost).ToList
    Dim list As List(Of Student) = New List(Of Student)
    For i As Integer = 0 To lines.Count - 1
        Dim data As String() = lines(i).Split(":"c)
        'Check data
        If data.Length >= 4 Then '
            list.Add(New Student() With {
                     .StudentName = data(0),
                     .StudentID = data(1),
                     .StudentDOB = data(2),
                     .StudentDOE = data(3)
                                        })
        End If
    Next
    StudentBindingSource.DataSource = list
End Sub

试试这个代码:

Dim list As List(Of Student) = New List(Of Student)(100)

基本上用一个容量初始化学生列表。这是列表的容量,不是count/length.