我们曾经在「Visual Basic 2005 档案 IO 与数据存取秘诀」一书的第 10 章说明如何使用 SqlBulkCopy 对象来执行大量复制作业。有读者询问,是否可以使用 SqlBulkCopy 对象将文字文件的内容大量复制到数据库。答案当然是肯定的?事实上,只要您能够将数据加载至一个 DataTable 对象或是利用 IDataReader 对象来加以读取,就可以使用 SqlBulkCopy 将其复制到 SQL Server 数据库内的数据表(Table)或检视表(View)当中。 <?xml:namespace prefix = o />
不过我们亲爱的读者在实际测试时遇到了一个问题,那就是他的文字文件内含 200 万笔数据列,因此在将文字文件复制到一个中介用的 DataTable 对象时便发生内存不足的情况?他询问我,该如何解决。
首先我要声明,要将一个内含 200 万笔数据列的文字文件大量复制到 SQL Server 数据库,想必不是一个经常性的作业,像这样的工作,其实可以考虑使用 SQL Server 2005 本身的公用程序与接口工具来完成,不一定非得在前端程序使用 SqlBulkCopy 对象不可。不过既然读者问了,我就试作了一次,结果令人满意。 
我的作法是,先剖析文字文件的内容以便正确地将数据列一笔接着一笔写入一个中介用的 DataTable 物件中,等到写满 50000 笔数据记录之后,就使用 SqlBulkCopy 对象将 DataTable 中的 50000 笔数据记录大量复制到 SQL Server 数据库,接着将 DataTable 对象中的所有数据记录清除,然后再继续从文字文件将后续的数据列读入DataTable对象中。反复依此进行,直到已大量复制完所有的数据记录为止。这样一批接着一批读取并大量复制的方式,可以避免发生内存不足的情况。 
                                图表 1
图表 1所示者是我所撰写之大量复制程序的接口。我的来源文字文件共内含 1,485,953 笔资料列(将近一百五十万笔),文字文件的档案大小达到 260MB,希望藉由这样的大量数据实作,来验证程序写法的正确性。至于程序代码完整列示如下: 
Option Strict On

' 汇入命名空间。
Imports Microsoft.VisualBasic.FileIO
Imports System.Data.SqlTypes
Imports System.Data.SqlClient

Public Class Form1

Private currentRow As String()
    Private myRowCount As Integer = 1
    Private myBatchCount As Integer = 1
    Private myCopiedRows As Long = 0
    Private countStart As Long

' 建立「章立民研究室」数据表,此处是当作一个中介数据表来使用。
    Private myTable As New DataTable("章立民工作室")

Private Sub btnParseTextFiles_Click(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles btnGoBulkCopy.Click

Me.btnGoBulkCopy.Enabled = False

' 建立「员工编号」字段。
        Dim colEmployeeId As DataColumn = _
            myTable.Columns.Add("员工编号", Type.GetType("System.Int32"))

' 建立「×××字号」字段。
        myTable.Columns.Add("×××字号", Type.GetType("System.String"))
        myTable.Columns("×××字号").MaxLength = 10
        myTable.Columns("×××字号").AllowDBNull = False

' 建立「姓名」字段。
        myTable.Columns.Add("姓名", Type.GetType("System.String"))
        myTable.Columns("姓名").MaxLength = 12

' 建立「性别」字段。
        myTable.Columns.Add("性别", Type.GetType("System.String"))
        'myTable.Columns("性别").MaxLength = 1

' 建立「地址」字段。
        myTable.Columns.Add("地址", Type.GetType("System.String"))
        myTable.Columns("地址").MaxLength = 41

' 建立「邮政编码」字段。
        myTable.Columns.Add("邮政编码", Type.GetType("System.String"))
        myTable.Columns("邮政编码").MaxLength = 5

' 建立「出生日期」字段。
        myTable.Columns.Add("出生日期", Type.GetType("System.DateTime"))

' 建立「婚姻状况」字段。
        myTable.Columns.Add("婚姻状况", Type.GetType("System.String"))

' 建立「雇用日期」字段。
        myTable.Columns.Add("雇用日期", Type.GetType("System.DateTime"))

' 建立「起薪」字段。
        myTable.Columns.Add("起薪", Type.GetType("System.Double"))

' 建立「目前薪资」字段。
        myTable.Columns.Add("目前薪资", Type.GetType("System.Double"))

' 建立「加薪日期」字段。
        myTable.Columns.Add("加薪日期", Type.GetType("System.DateTime"))

' 建立「部门」字段。
        myTable.Columns.Add("部门", Type.GetType("System.String"))
        myTable.Columns("部门").MaxLength = 10

Using myReader As New TextFieldParser("Text章立民工作室.txt")

' 表示档案内容是字符分隔。
            myReader.TextFieldType = FieldType.Delimited

' 定义文字文件的字符分隔符。
            myReader.Delimiters = New String() {","}

' 循环处理文字文件中所有数据列的所有字段。
            While Not myReader.EndOfData

Try
                    currentRow = myReader.ReadFields()

' 略过标题列
                    If myRowCount > 1 Then
                        myTable.Rows.Add(currentRow)
                    End If
                Catch ex As MalformedLineException
                    MessageBox.Show(ex.Message)
                    Exit Sub
                End Try

myRowCount += 1
                Me.lblBeingCopyedTextRows.Text = myTable.Rows.Count.ToString
                Me.lblBeingCopyedTextRows.Refresh()

If myTable.Rows.Count = 50000 Then
                    Try
                        GoBulkCopy()
                    Catch ex As Exception
                        MessageBox.Show(ex.Message)
                        Exit Sub
                    End Try
                    ' 清空资料表。
                    myTable.Rows.Clear()
                    myBatchCount += 1
                End If
            End While

' 复制最后一批不足50000 笔的数据记录。
            If myTable.Rows.Count > 0 Then
                GoBulkCopy()
            End If
        End Using

Me.lblBeingCopyedTextRows.Text = myTable.Rows.Count.ToString
        Me.lblTextFileRowCount.Text = _
          "来源文字文件的数据笔数:" & (myRowCount - 2).ToString
        Me.btnGoBulkCopy.Enabled = True
    End Sub

Private Sub GoBulkCopy()
        ' 利用SqlConnectionStringBuilder 对象来构建连接字符串。
        ' 由于本范例是在同一个SQL Server 数据库的不同数据表之间进行大量复制作业,
        ' 因此连接至来源数据库与连接至目标服务器的连接字符串是相同的。
        Dim sqlconStringBuilder As New SqlConnectionStringBuilder()
        sqlconStringBuilder.DataSource = "(local)SQLExpress"
        sqlconStringBuilder.InitialCatalog = "北风贸易"
        sqlconStringBuilder.IntegratedSecurity = True

' 建立连结至目标SQL Server 数据库的连接。
        Using con_bulkcopy As New _

            SqlConnection(sqlconStringBuilder.ConnectionString)

' 开启连接至目标SQL Server 的连接。
            con_bulkcopy.Open()

Dim cmdRowCount As New SqlCommand( _
              "SELECT COUNT(*) FROM dbo.Bulk_Target_章立民工作室;", _
              con_bulkcopy)

If myBatchCount = 1 Then
                ' 计算出目标数据表在执行大量复制作业前有多少笔数据记录。
                countStart = System.Convert.ToInt32(cmdRowCount.ExecuteScalar())
                Me.lblRowsCountBeforeBulkCopy.Text = _
                  "目标数据表在大量复制前拥有的数据笔数= " & countStart.ToString
                Me.lblRowsCountBeforeBulkCopy.Refresh()
            End If

' 建立一个SqlBulkCopy 对象以便执行大量复制作业。
            Using bcp As SqlBulkCopy = New SqlBulkCopy(con_bulkcopy)

' 指定目标数据表的名称。
                bcp.DestinationTableName = "dbo.Bulk_Target_章立民工作室"

' 如果来源数据表与目标数据表的各个字段顺序没有完全对应,
                ' 必须在此设定来源字段与目标字段的对应关系。

' 将来源数据写入目标数据表。
                bcp.WriteToServer(myTable)

End Using

' 最后再计算出大量复制了多少笔数据记录。
            Dim countEnd As Long = _
              System.Convert.ToInt32(cmdRowCount.ExecuteScalar())

' 计算出累计复制笔数。
            myCopiedRows = countEnd – countStart

' 显示出批次与大量复制累计笔数。
            Me.DataGridView1.Rows.Add( _
              New String() {CStr(myBatchCount), CStr(myCopiedRows)})
            Me.DataGridView1.Refresh()

End Using
    End Sub
End Class

后记:
说真的,这个程序花不到我半小时,但是制作仿真的文字文件并等待程序执行,倒是花了我不少时间。不过,能解决使用者的问题,心中的大石头总算落了地。最近又要开始赶下一本书,全体成员有得忙了唷。

转载于:https://blog.51cto.com/liminzhang/53402

ADO.NET 2.0 - 读者询问能否使用 SqlBulkCopy 对象来大量复制文字文件相关推荐

  1. ADO.NET 2.0 中的新增 DataSet 功能

    发布日期: 1/13/2005 | 更新日期: 1/13/2005 Jackie Goldstein Renaissance Computer Systems 适用于: Microsoft ADO.N ...

  2. ADO.NET 2.0 功能一览

    ADO.NET 2.0 功能一览 作者:Bob Beauchemin(DevelopMentor) 相关技术:ADO.NET 2.0.SQL Server 2005 难度:★★★☆☆ 读者类型:.NE ...

  3. ADO.NET 2.0中的SqlCommand.ExecutePageReader

    http://blog.joycode.com/liuhuimiao/ 在.NET 2.0 PDC或Beta1中,可以看到SqlCommand对象新增了个ExecutePageReader方法,该方法 ...

  4. ADO.NET 2.0 中的架构

    Bob Beauchemin DevelopMentor 适用于: Microsoft ADO.NET 2.0 Microsoft Visual Studio 2005 C# 编程语言 摘要:了解在 ...

  5. ADO.NET 2.0 功能一览 --作者:Bob Beauchemin

    [导读]ADO.NET 2.0包含一个新的基类提供程序模型,适用于所有提供程序的功能以及对System.Data.SqlClient进行的更改.通过本文,您可以获得有关这些新功能的概述.它们的用法示例 ...

  6. System.Data.SQLite(SQLite ADO.NET 2.0的提供程序,已经包含Sqlite引擎)

    今天在研究其他的技术的时候,重新查看了一下Sqlite在.NET下的最新实现.结果发现这样一个好东西.下面把其首页的说明翻译如下: System.Data.SQLite 是一个原始SQLite的加强版 ...

  7. ASP.NET 2.0编程技巧之用Response对象输出图像

    一. 简介 作为ASP.NET基本对象之一的Response对象不但可以通过Write()方法直接在页面上输出字符串数据,而且还可以使用BinaryWrite()方法直接显示二进制表示的数据,如图像. ...

  8. Py:利用pyautogui实现自动将pdf文件(需手动设定pdf总页数)自动翻页并截取另存为图片形式,或自动隔0.1秒自动截笔记本全屏保存到指定文件夹

    Py:利用pyautogui实现自动将pdf文件(需手动设定pdf总页数)自动翻页并截取另存为图片形式,或自动隔0.1秒自动截笔记本全屏保存到指定文件夹 目录 实现步骤和结果 核心代码 实现步骤和结果 ...

  9. Fluid 0.4 新版本正式发布:支持数据预热,优化小文件场景

    作者 | 顾荣 Photo Creidt @ 轻零 导读:为了解决大数据.AI 等数据密集型应用在云原生计算存储分离场景下,存在的数据访问延时高.联合分析难.多维管理杂等痛点问题,南京大学 PASAL ...

最新文章

  1. video标签支持获取rtsp流么_Flask教程(二十二)在浏览器中播放rtsp实时流
  2. git stash pop_git常用命令行背诵并默写(全)
  3. apache2.2配置
  4. unity3d鼠标拖拽模型,旋转模型
  5. 入门代码教程第二节 如何:实现服务协定
  6. java之List常用方法(一),Java 常用方法
  7. VC++基于APR实现禁止某个业务(开发行为控制软件用得着,例如上班禁止上QQ)...
  8. 将Java EE与jOOQ结合使用的初学者指南
  9. 番茄钟怎么调_不一样的番茄计时 APP,让番茄钟回归效率的本质
  10. HDU5688 Problem D【字符串排序+MAP】
  11. C++基础教程之指针
  12. Window 远程连接 Ubuntu 系统
  13. 中学《教育知识与能力》复习笔记-教资复习全靠它~背诵资料
  14. Win7/10 远程桌面发生验证错误 要求的函数不受支持 一键解决
  15. 使用Android Studio 开发APP入门经验
  16. 收藏 | 22个短视频学习Adobe Illustrator论文图形编辑和排版
  17. android菜鸡提升之路---实现一个积木拼图游戏
  18. 微信公众号主体注销了,如何办理账号迁移?
  19. 多模、AI 齐上阵,Deepfake 换脸术克星驾到!
  20. Python的编译器

热门文章

  1. jQuery温度计,支持摄氏度华氏度同时展示
  2. MySQL的并发控制与加锁分析
  3. SpringBoot使用教程【1】Restful API设计 返回json,xml格式...
  4. 陌陌股价过山车背后隐藏了什么?
  5. 构建之法第四、第五章读后感
  6. Eclipse 中maven插件坏死解决办法
  7. 直接拿来用!最火的iOS开源项目
  8. 在MAC下安装redis以及其PHP扩展
  9. Error: unterminated string literal。通常原因是输出字符str中包含换行符导致的。
  10. sql server 关键字 三