【发布时间】:2020-09-29 16:16:38
【问题描述】:
我正在以DataTable 的形式从数据库中获取数据,并且需要在 VB.NET 中转换为 CSV 字符串。
【问题讨论】:
我正在以DataTable 的形式从数据库中获取数据,并且需要在 VB.NET 中转换为 CSV 字符串。
【问题讨论】:
使用 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", ...})
【讨论】:
.Columns 集合中推断出标题。那么您只需要该方法的一个参数:CSVBuilder(dt)。最后,我可能更喜欢返回一个流,或者请求一个流写入。
.Columns 集合中传递数据表列,但我认为对于 CSV 文件标题,仍然需要将标题列表传递给 CSVBuilder 方法。您是否有更好的想法来管理数据表中的标题并将该数据表仅传递给 CSVBuilder 方法?
回应评论,因为这不适合那个空间:
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 会有所帮助,但不会完全消除这些问题。写入通常连接到磁盘上的文件的流,使您有机会完全消除此问题。另外,它可能会为您节省以后的工作。
【讨论】: