【问题标题】:Seek through CSV for column with specific header通过 CSV 查找具有特定标题的列
【发布时间】:2012-05-17 14:35:12
【问题描述】:

我正在开发一个程序,您可以从 csv 文件中选择一个标题(它最初会解析标题)并且我希望用户能够获取列的数据而无需读取整个文件。(制作一个字符串数组的列表,并为信息提取字符串数组索引,这是简单易行的事情)。

有没有办法我可以使用 seek 来做到这一点?也许搜索一个字符串(这将是标题)并在其列中获取信息。

这是 getHeader 函数,以防万一……

private string[] getHeader(string path)//gets the headers from the file path specified.
    {          
        List<string> row = new List<string>();

        using (StreamReader readFile = new StreamReader(path))
        {          
            row = (readFile.ReadLine().Split(',').ToList());                
        }

        return row.ToArray();

    }

(to list 和 to array 只是为了绕过最初为数组设置大小...)

谢谢!

【问题讨论】:

  • 不清楚你想达到什么目标......你能更好地解释一下你的目标是什么吗?
  • Split 无论如何都会返回一个数组,因此您可以安全地使用return readFile.ReadLine().Split(',')。至于列的事情,除非你有固定宽度的列,我想你能做的最好的就是通读文件。
  • 需要注意的一点是,如果数据包含逗号并且您必须使用引号分隔的文本,则调用 Split 将不起作用。在这种情况下,您实际上必须进行一些解析。
  • ToList、ToArray 调用是多余的,只需将 row 声明为 string[] row = null; int 与您现在使用 List 的位置相同。拆分不会填充现有数组。它会创建一个新的。

标签: c# csv filestream seek


【解决方案1】:

不可能。

Seek 可以转到文件中的确定位置。如果您有一个固定长度的记录 (SDF/COBOL) 文件,其中记录长度很大且记录很少,这将是一个不错的主意。

不幸的是,.csv 根据定义是可变长度记录。您只能根据在记录末尾点击 cr/lf 来判断一条记录在哪里停止和开始。

即使对于大多数固定记录格式,这也不是一个好主意。由于缓冲,操作系统无论如何都会读取整个文件,因为您将寻找比操作系统预加载的更小的数量。

我明白你为什么要这样做;直觉上,听起来会更快。虽然您应该始终牢记速度来设计代码,但这已经足够低级,可以称为“过早的优化” - 谷歌。基本上你必须通过编写它来向自己证明它运行缓慢,然后,当你看到它对功能的巨大障碍时,你可以进行优化。

不要自己解析!

MS 有一个解决方案。 Microsoft.VisualBasic.FileIO.TextFieldParser。是的,您可以将它与 C# 一起使用(即使下面的示例在 VB 中,您也可以弄清楚您需要做什么)。不要为包含对 VB 的引用而感到自豪。口袋里的时间和金钱很重要,不能说“我不会用 10 英尺长的杆子碰任何 VB”。更改是程序集已经在您的目标 PC 上。唯一需要注意的是您是否有程序安装包下载大小问题,或者正在部署到非 PC 平台。

    Using Reader As New Microsoft.VisualBasic.FileIO.TextFieldParser(CSVPath)

        Reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
        Reader.Delimiters = New String() {","}
        Reader.TrimWhiteSpace = True
        Reader.HasFieldsEnclosedInQuotes = True

        While Not Reader.EndOfData
            Try
                Dim st2 As New List(Of String)
                st2.addrange(Reader.ReadFields())
                If iCount > 0 Then ' ignore first row = field names
                    Dim p As New clsPerson
                    p.CSVLine = st2
                    While p.CSVLine.Count < 15
                        p.CSVLine.Add("")
                    End While
                    p.FirstName = st2(1).Trim
                    If st2.Count > 2 Then
                        p.MiddleName = st2(2).Trim
                    Else
                        p.MiddleName = ""
                    End If
                    p.LastNameSuffix = st2(0).Trim
                    If st2.Count >= 6 Then
                        p.TestCase = st2(5).Trim
                    End If
                    If st2(3) > "" Then
                        p.CertsFromCase.Add(st2(3))
                    End If
                    cases.Add(p)
                Else
                    stFirstRow = CatLine(st2.ToArray)
                    Dim st3(6) As String
                    For kk As Integer = 0 To Math.Min(st2.Count - 1, 5)
                        st3(kk) = st2(kk)
                    Next
                    If 0 = InStr(st3(0), "Last Name", CompareMethod.Text) Or _
                     0 = InStr(st3(1), "First Name", CompareMethod.Text) Or _
                     0 = InStr(st3(2), "Middle Name", CompareMethod.Text) Or _
                     0 = InStr(st3(3), "Policy", CompareMethod.Text) Or _
                     0 = InStr(st3(5), "Test Case", CompareMethod.Text) Then
                        stFirstRow = "Last Name,First Name,Middle Name,Policy,,Test Case #" & vbCrLf & stFirstRow
                    End If
                End If
            Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
                MsgBox("Line " & ex.Message & " is not valid and will be skipped.")
            End Try
            iCount += 1
        End While
    End Using

【讨论】:

  • 谢谢。我意识到我没有完全理解 seek 的工作原理,因为同事向我错误地解释了它......
猜你喜欢
  • 1970-01-01
  • 2013-12-06
  • 1970-01-01
  • 1970-01-01
  • 2017-05-10
  • 1970-01-01
  • 1970-01-01
  • 2017-05-14
  • 1970-01-01
相关资源
最近更新 更多