使用 OleDB/Jet 导入 DataTable

Posted

技术标签:

【中文标题】使用 OleDB/Jet 导入 DataTable【英文标题】:Import to DataTable using OleDB/Jet 【发布时间】:2016-05-30 16:45:22 【问题描述】:

我用 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 行并将它们传递给另一个函数 step for step,它应该在 for 循环中更好地工作,因为 jet oledb 不会读取大于 1 GB 的文件

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

但它通常只适用于字符串

    我需要识别整数、双精度、字符串等数据类型。我的第一个想法是通过 sql 查询并通过 tryparse 检查表

    Dim dtInserts As DataTable = db.GetDataTable("SELECT TOP 0 * FROM " & _table) 将 ListOfTypes 暗淡为新列表(System.Type) 对于 dtInserts.Columns 中的每个 _col 作为 DataColumn 暗淡 _type 作为 System.Type = _col.DataType ListOfTypes.Add(_type) 下一个 暗淡 _wert1 As String = "11.11.2011" Dim _type1 As System.Type = ListOfTypes.Item(1) If DateTime.TryParse(_wert1, New Date) Then 万一

    但仍然不确定它是否会起作用

    所有已读取的数据都应编码在 1252 代码页中。 这个真的不行

Dim ConStr As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & TextBox1.Text & ";Extended Properties=""TEXT;HDR=Yes;FMT=Delimited;CODEPAGE=1252"""

有人知道可以做什么吗?

【问题讨论】:

请一次提出 1 个问题,将 4 个问题捆绑在一起会使发布简短答案的范围太广且太难。 看这里***.com/questions/14044727/…***.com/questions/1499397/… #3 和#4 非常可行,#2 太模糊,没有样本数据,无法理解您要做什么,#1 可能可以原生完成取决于数据,否则您可能需要添加一个步骤。如果您将问题细化为不那么广泛的问题,您可能会在结束之前得到一些答案 你应该删除Application.DoEvents()这一行——它会导致奇怪的事情发生。 如果需要解析CSV文件,可以使用CSV解析器。 TextFieldParser class 可能就足够了。那么您的程序将不受 JET 的限制。 【参考方案1】:

CSVHelper 可以做大部分你想做的事。 FileHelpers 也可能有用,只是我没有使用它。我不推荐 VB 的 TextFieldParser,因为它返回的是字符串数组而不是类型数据。

OleDB 提供了一种很好的导入方式,但保存到数据库中却是一个小挑战。所有加载的行都将有一个RowStateUnchanged。将其更改为 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

我不能给出一个完整的使用教程,但通常你创建一个类型(类),它定义了每一列的数据类型(这里,RandItem),RandItemMap 是另一个类,它指定文件中这些属性的顺序。这样做时,CSVHelper 知道每一列的数据类型,并会为您转换。

有几种使用方法,这种方法是从文件中一次读取一行并立即将该项目保存到数据库中:csvData = csv.GetRecords(Of OleImportItem)()csvData 初始化为IEnumberable(Of RandItem),所以只有 在循环中一次加载一个项目,这使得它非常经济。

在循环中,代码从 csv 文件中获取输入的 item,然后将其映射到相应的参数并保存。这比将数据批量复制到DataTable并保存快20%左右;由于只加载了 1 个项目,因此占用的内存要少得多。


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

注意导入/解析不带标题的文本文件与显示的略有不同,但同样简单。

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

【讨论】:

csv helper 是一个好方法,但我对流式阅读器的体验非常糟糕,因为读取大文件需要几个小时,有没有办法读取以 1252 编码并替换为字符的文件? 我非常怀疑流式阅读器会成为瓶颈。使用上面的代码,它将 100k 行读入一个类型化的对象。我没有对它做任何事情,因为对象是为 StreamReader 计时的。但是,这确实意味着创建了一个对象,并将非平凡的行数据解析并复制到其中。经过的时间:903 毫秒。但是一个 1GB 的文件需要时间。项目符号 2 中的内容也需要时间 - 字符串是不可变的,因此一行创建 5 个连续复制数据位到每个。 1252 没有什么特别之处——它是 windows 默认编码。 另一个测试,这次将所有 100k 记录以 10k 的批次发布到 mysql DB:不到 2 分钟。更多行将花费更多时间,而您对它们执行的操作将花费更多时间。 @Sparkm4n 你知道文件中有多少行吗?我正在用 Dapper 测试一些东西,我想到了这个 Q(因为我正在用相同的数据进行测试)。 我有几个大文件,最大的一个大约有。一百万行

以上是关于使用 OleDB/Jet 导入 DataTable的主要内容,如果未能解决你的问题,请参考以下文章

我应该通过 OleDb Jet4.0 读取一个 excel 文件并保存到数据集中吗?

使用 Asp.net 将 Excel 导入 DataTable

Excel操作--使用NPOI导入导出Excel为DataTable

请问datatable能不能直接导入excel中??

Excel 导入到Datatable 中,再使用常规方法写入数据库

将 Excel 导入 DataTable 字符串为空