我用Oledb编写了一个简短的函数,它应该读取大量的数据,但仍有几个问题我无法解决,它是关于在sql数据库中读取和插入分号分隔的数据
Private Function GetCSVFile(ByVal file As String) As DataTable
Try
Dim dt As New DataTable
Dim ConStr As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & TextBox1.Text & ";Extended Properties=""TEXT;HDR=Yes;FMT=Delimited"""
Dim conn As New OleDb.OleDbConnection(ConStr)
Dim da As New OleDb.OleDbDataAdapter("Select * from " & _table & ".csv", conn)
da.Fill(dt)
Application.DoEvents()
getData = dt
Catch ex As OleDbException
MessageBox.Show(ex.Message)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Return getData
End Function
1。它读取整个文件,但我需要告诉函数它应该只读取50.000行并将它们传递给另一个函数步骤,它应该更好地用于for循环,因为jet oledb不会读取大于1 GB的文件
value(i) = value(i).Replace("\t", Constants.vbTab).Replace("\n", Constants.vbLf).Replace("\r", Constants.vbCr).Replace("\""", """").Replace("\\", "\")
但它通常仅适用于字符串
我需要识别整数,双精度,字符串等数据类型。我的第一个想法是通过sql查询来做,并通过tryparse检查表
Dim dtInserts As DataTable = db.GetDataTable("SELECT TOP 0 * FROM " & _table) Dim ListOfTypes As New List(Of System.Type) For Each _col As DataColumn In dtInserts.Columns Dim _type As System.Type = _col.DataType ListOfTypes.Add(_type) Next Dim _wert1 As String = "11.11.2011" Dim _type1 As System.Type = ListOfTypes.Item(1) If DateTime.TryParse(_wert1, New Date) Then End If
但仍不确定它是否可行
所有已读取的数据都应在1252 Codepage中编码。 这个没有真正起作用
Dim ConStr As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & TextBox1.Text & ";Extended Properties=""TEXT;HDR=Yes;FMT=Delimited;CODEPAGE=1252"""
任何人都知道可以做些什么?
答案 0 :(得分:2)
CSVHelper可以完成您想要的大部分内容。 FileHelpers也可能有用,我只是没有那么多。我不推荐VB的TextFieldParser
因为它返回一个字符串数组而不是键入的数据。
OleDB
提供了一种很好的导入方式,但保存到数据库提出了一个小小的挑战。所有加载的行都将RowState
Unchanged
。将其更改为Added
的唯一方法是将行复制到新表中:
For Each dr As DataRow In dtCSV.Rows
dtDest.Rows.Add(dr.ItemArray)
Next
它会工作,但结果是,您将有2个表,并且所有这些行一次加载。事实证明,使用CSVHelper和简单的INSERT查询是最经济的 - 因为记录是从IEnumerable<T>
获取的,所以一次只能加载1个源记录。它比复制行快一点:在500k行上快20%左右。
注意:除了以分号分隔之外,我们不知道数据是什么样的......而且显然有很多。
Using sr As New StreamReader(CSVFilePath, False),
csv As New CsvReader(sr)
' some CSVHelper config options
csv.Configuration.HasHeaderRecord = True
csv.Configuration.TrimFields = True
csv.Configuration.TrimHeaders = True
csv.Configuration.Delimiter = ";"
csv.Configuration.IsHeaderCaseSensitive = False
csv.Configuration.RegisterClassMap(Of RandItem.RandItemMap)()
' get the file into IEnumerable collection
Dim csvData = csv.GetRecords(Of OleImportItem)()
Dim SQL = <sql>
INSERT INTO RandomData
(Foo, Bar, Cat, Dog...)
VALUES
(@p1, @p2, @p3, @p4...)
</sql>.Value
Using dbcon As New OleDbConnection(ACEConnStr)
Using cmd As New OleDbCommand(SQL, dbcon)
dbcon.Open()
' create the parameters
cmd.Parameters.Add("@p1", OleDbType.VarChar)
cmd.Parameters.Add("@p2", OleDbType.VarChar)
cmd.Parameters.Add("@p3", OleDbType.Integer)
cmd.Parameters.Add("@p4", OleDbType.Integer)
...
' load one item at a time, to save it
For Each item In csvData
cmd.Parameters("@p1").Value = item.Foo
cmd.Parameters("@p2").Value = item.Bar
cmd.Parameters("@p3").Value = item.Cat
cmd.Parameters("@p4").Value = item.Dog
...
cmd.ExecuteNonQuery()
Next
End Using
End Using
End Using
我无法提供有关如何使用它的完整教程,但通常会创建一个类型(Class)来定义每列的数据类型(此处为RandItem
),RandItemMap
是另一个class,指定文件中这些属性的顺序。这样做,CSVHelper知道每列的数据类型并将为您转换。
有几种方法可以使用它,这种方式是从文件中一次读取一行并立即将该项目保存到数据库:csvData = csv.GetRecords(Of OleImportItem)()
将csvData
初始化为IEnumberable(Of RandItem)
,因此在循环中一次仅加载一个项目,这使得它非常经济。
在循环中,代码从csv文件中获取一个类型item
,然后将其映射到相应的参数并保存。这比批量复制数据和保存数据快20%左右;因为只加载了1个项目,因此内存密集程度更低。
对于较小的csv文件,您可以使用.ToArray()
或ToList()
将文件加载到集合中。
注意导入/解析没有标题的文本文件与显示的有点不同,但同样简单。
听起来像CSVHelper可以消除洗衣清单中的大多数问题。