使用 OleDB/Jet 导入到 DataTable

Import to DataTable using OleDB/Jet

我用 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 的文件

  1. 我需要替换字符
    value(i) = value(i).Replace("\t", Constants.vbTab).Replace("\n", Constants.vbLf).Replace("\r", Constants.vbCr).Replace("\""", """").Replace("\", "\")

但它通常只适用于字符串

  1. 我需要识别整数、双精度、字符串等数据类型。我的第一个想法是通过 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
    

    但仍不确定它是否有效

  2. 所有读取的数据都应该用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""" 

有人知道可以做什么吗?

CSVHelper can do most of what it sounds like you want. FileHelpers 也可能有用,我只是没怎么用过它。我不会推荐 VB 的 TextFieldParser 因为它 returns 是一个字符串数组而不是类型化数据。

OleDB 提供了一种很好的导入方式,但保存到数据库是一个小挑战。所有加载的行的 RowStateUnchanged。将其更改为 Added 的唯一方法是将行复制到新的 table:

For Each dr As DataRow In dtCSV.Rows
    dtDest.Rows.Add(dr.ItemArray)
Next

它会起作用,但结果是,您将同时加载 2 table 和所有这些行。事实证明,使用 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,然后将其映射到相应的参数并保存。这比将数据批量复制到DataTable并保存快20%左右;而且内存占用更少,因为只加载了 1 个项目。


对于较小的 csv 文件,您可以使用 .ToArray()ToList() 将文件加载到 collection。

注意 Importing/parsing 没有 headers 的文本文件与显示的略有不同,但同样简单。

听起来 CSVHelper 可能会解决您洗衣清单中的大多数问题。