【问题标题】:how to create CSV string from DataTable in VB.NET?如何在 VB.NET 中从 DataTable 创建 CSV 字符串?
【发布时间】:2020-09-29 16:16:38
【问题描述】:

我正在以DataTable 的形式从数据库中获取数据,并且需要在 VB.NET 中转换为 CSV 字符串。

【问题讨论】:

    标签: vb.net csv datatable


    【解决方案1】:

    使用 DataTable、CSV Headers、DataTable Columns 参数创建通用方法:

        Private Function CSVBuilder(dt As DataTable, headers As List(Of String), columns As List(Of String)) As String
            Dim sCSV = New StringBuilder(String.Join(",", headers))
            sCSV.Append(Environment.NewLine)
    
            Dim view As New DataView(dt)
            Dim tDt As DataTable = view.ToTable(True, columns.ToArray)
    
            For Each row As DataRow In tDt.Rows
                '-- Handle comma
                sCSV.Append(String.Join(",", (From rw In row.ItemArray Select If(rw.ToString.Trim.Contains(","), String.Format("""{0}""", rw.ToString.Trim), rw.ToString.Trim))))
                sCSV.Append(Environment.NewLine)
            Next
    
            Return sCSV.ToString
        End Function
    

    然后调用你的代码来获取 CSV 字符串:

    CSVBuilder(dataTable,
               New List(Of String) From {"Header Column 1", "Header Column 2", ...},
               New List(Of String) From {"DataTableColumn1", "DataTableColumn2", ...})
    

    【讨论】:

    • 看起来像一个奇怪的 API 表面。我认为您会编写该方法来假设数据表 已经 具有正确的列,或者直接询问 DataView。此外,我会从数据表中的.Columns 集合中推断出标题。那么您只需要该方法的一个参数:CSVBuilder(dt)。最后,我可能更喜欢返回一个流,或者请求一个流写入。
    • @JoelCoehoorn,感谢您的回复。是的,我可以在.Columns 集合中传递数据表列,但我认为对于 CSV 文件标题,仍然需要将标题列表传递给 CSVBuilder 方法。您是否有更好的想法来管理数据表中的标题并将该数据表仅传递给 CSVBuilder 方法?
    【解决方案2】:

    回应评论,因为这不适合那个空间:

    Private Function CSVBuilder(dt As DataTable) As String
        Dim sCSV As New StringBuilder()
    
        'Headers
        Dim delimeter As String = ""
        For Each col As String In dt.Columns.Select(Func(col) col.ColumnName)
             If col.Contains(",") Then col = """" & col & """"
              sCSV.Append(delimeter).Append(col)
              delimeter = ","
        Next
        sCSV.AppendLine()
    
        For Each row As DataRow In tDt.Rows
            sCSV.AppendLine(String.Join(",", (From rw In row.ItemArray Select If(rw.ToString.Trim.Contains(","), String.Format("""{0}""", rw.ToString.Trim), rw.ToString.Trim))))
        Next
    
        Return sCSV.ToString
    End Function
    

    现在,我确实删除了这段代码:

    Dim view As New DataView(dt)
    Dim tDt As DataTable = view.ToTable(True, columns.ToArray)
    

    但我不会将此作为CSVBuilder() 方法的一部分。如果您想投影表的特定视图,我会与创建 CSV 数据分开进行。你可以为它创建一个单独的方法:

    Public Function GetProjection(dt As DataTable, columns As IEnumerable(Of String)) As DataTable
        Dim view As New DataView(dt)
        Return view.ToTable(True, columns.ToArray())
    End Function
    

    然后你这样称呼它们:

     Dim dt As DataTable = '.... original table here
     Dim columns() As String = '... the columns you want
    
     Dim csv As String = CSVBuilder(GetProjection(dt, columns))
    

    或者像这样:

     Dim dt As DataTable = '.... original table here
     Dim columns() As String = '... the columns you want
    
     Dim dt1 = GetProjection(dt, columns)
     Dim csv As String = CSVBuilder(dt1)
    

    这叫Currying,这是一件好事。

    最后,我将重复我的建议,即从写入流的角度进行思考。带有重复附加操作的长字符串可能会给 .Net 垃圾收集器带来真正的问题。使用StringBuilder 会有所帮助,但不会完全消除这些问题。写入通常连接到磁盘上的文件的流,使您有机会完全消除此问题。另外,它可能会为您节省以后的工作。

    【讨论】:

    • 我会对此做更多的实验。所以我正在处理电子邮件附件中的 CSV 发送。如果您有任何好的代码示例,我可以参考并使用 Stream 在电子邮件中发送 CSV 文件,这将有很大帮助。
    猜你喜欢
    • 2012-05-29
    • 2014-07-12
    • 2018-10-23
    • 2016-02-28
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多