将数据从 Visual Basic 传输到 Excel 的方法

摘要

本文讨论从 Microsoft Visual Basic 应用程序将数据传输到 Microsoft Excel 的多种方法。 本文还介绍了每种方法的优点和缺点,以便你可以选择最适合你的解决方案。

更多信息

最常用于将数据传输到 Excel 工作簿的方法是自动化。 自动化为你提供了最大的灵活性,可以指定数据在工作簿中的位置,以及在运行时设置工作簿的格式和进行各种设置。 借助自动化,可以使用多种方法来传输数据:

  • 逐个单元格传输数据
  • 将数组中的数据传输到单元格区域
  • 使用 CopyFromRecordset 方法将 ADO 记录集中的数据传输到单元格区域
  • 在 Excel 工作表上创建一个 QueryTable,其中包含 ODBC 或 OLEDB 数据源上的查询结果
  • 将数据传输到剪贴板,然后将剪贴板内容粘贴到 Excel 工作表中

还有一些方法可用于将数据传输到 Excel,这些方法不一定需要自动化。 如果运行应用程序服务器端,则这是一种很好的方法,用于从客户端中处理大量数据。 以下方法可用于在不使用自动化的情况下传输数据:

  • 将数据传输到制表符或逗号分隔的文本文件,Excel 稍后可以将其分析为工作表上的单元格
  • 使用 ADO 将数据传输到工作表
  • 使用动态数据交换 (DDE) 将数据传输到 Excel

以下部分提供有关其中每个解决方案的更多详细信息。

注意 使用 Microsoft Office Excel 2007 时,可以在保存工作簿时使用新的 Excel 2007 工作簿 (*.xlsx) 文件格式。 为此,请在以下代码示例中找到以下代码行:

oBook.SaveAs "C:\Book1.xls"

将此代码替换为以下代码行:

oBook.SaveAs "C:\Book1.xlsx"

此外,默认情况下,Northwind 数据库不包括在 Office 2007 中。 但是,可以从 Microsoft Office Online 下载 Northwind 数据库。

使用自动化逐个单元格传输数据

使用自动化,可以一次将数据传输到工作表一个单元格:

Dim oExcel As Object    
Dim oBook As Object    
Dim oSheet As Object 
    
'Start a new workbook in Excel    
Set oExcel = CreateObject("Excel.Application")    
Set oBook = oExcel.Workbooks.Add
      
'Add data to cells of the first worksheet in the new workbook    
Set oSheet = oBook.Worksheets(1)    
oSheet.Range("A1").Value = "Last Name"    
oSheet.Range("B1").Value = "First Name"    
oSheet.Range("A1:B1").Font.Bold = True    
oSheet.Range("A2").Value = "Doe"    
oSheet.Range("B2").Value = "John"     

'Save the Workbook and Quit Excel    
oBook.SaveAs "C:\Book1.xls"    
oExcel.Quit

如果数据量很小,则逐个单元格传输数据可能是一种完全可接受的方法。 可以灵活地将数据放在工作簿中的任何位置,并且可以在运行时有条件地设置单元格的格式。 但是,如果有大量数据要传输到 Excel 工作簿,则不建议使用此方法。 在运行时获取的每个 Range 对象都会产生接口请求,因此以这种方式传输数据的速度可能会很慢。 此外,Microsoft Windows 95 和 Windows 98 对接口请求有 64K 限制。 如果对接口请求达到或超过此 64k 限制,则自动化服务器 (Excel) 可能会停止响应,或者可能会收到指示内存不足的错误。

再一次,仅对少量数据可以接受逐个单元格传输数据。 如果需要将大型数据集传输到 Excel,应考虑稍后介绍的解决方案之一。

有关自动化 Excel 的更多示例代码,请参阅 如何从 Visual Basic 自动执行 Microsoft Excel

使用自动化将数据数组传输到工作表上的区域

一个数据数组可以一次传输到多个单元格区域:

Dim oExcel As Object    
Dim oBook As Object    
Dim oSheet As Object     

'Start a new workbook in Excel    
Set oExcel = CreateObject("Excel.Application")    
Set oBook = oExcel.Workbooks.Add     

'Create an array with 3 columns and 100 rows    
Dim DataArray(1 To 100, 1 To 3) As Variant    
Dim r As Integer    
For r = 1 To 100       
   DataArray(r, 1) = "ORD" & Format(r, "0000")       
   DataArray(r, 2) = Rnd() * 1000       
   DataArray(r, 3) = DataArray(r, 2) * 0.7    
Next     

'Add headers to the worksheet on row 1    
Set oSheet = oBook.Worksheets(1)    
oSheet.Range("A1:C1").Value = Array("Order ID", "Amount", "Tax")     

'Transfer the array to the worksheet starting at cell A2    
oSheet.Range("A2").Resize(100, 3).Value = DataArray        

'Save the Workbook and Quit Excel    
oBook.SaveAs "C:\Book1.xls"    
oExcel.Quit

如果使用数组而不是逐个单元格传输数据,则可以使用大量数据实现巨大的性能提升。 请考虑上述代码中的以下行,该行将数据传输到工作表中的 300 个单元格:

   oSheet.Range("A2").Resize(100, 3).Value = DataArray

此行表示两个接口请求, (一个用于 Range 方法返回的 Range 对象,另一个用于 Resize 方法返回的 Range 对象) 。 另一方面,按单元格传输数据单元格需要向 Range 对象请求 300 个接口。 只要有可能,就可以从批量传输数据并减少发出的接口请求数中受益。

使用自动化将 ADO 记录集传输到工作表区域

Excel 2000 引入了 CopyFromRecordset 方法,该方法允许将 ADO (或 DAO) 记录集传输到工作表上的区域。 以下代码演示了如何使用 CopyFromRecordset 方法自动执行 Excel 2000、Excel 2002 或 Office Excel 2003 以及传输 Northwind 示例数据库中订单表的内容。

'Create a Recordset from all the records in the Orders table    
Dim sNWind As String    
Dim conn As New ADODB.Connection    
Dim rs As ADODB.Recordset    
sNWind = _       
   "C:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb"    conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _       sNWind & ";"    
conn.CursorLocation = adUseClient    
Set rs = conn.Execute("Orders", , adCmdTable)        

'Create a new workbook in Excel    
Dim oExcel As Object    
Dim oBook As Object    
Dim oSheet As Object    
Set oExcel = CreateObject("Excel.Application")    
Set oBook = oExcel.Workbooks.Add    
Set oSheet = oBook.Worksheets(1)        

'Transfer the data to Excel    
oSheet.Range("A1").CopyFromRecordset rs        

'Save the Workbook and Quit Excel    
oBook.SaveAs "C:\Book1.xls"    
oExcel.Quit        
'Close the connection    
rs.Close    
conn.Close

注意 如果使用 Office 2007 版本的 Northwind 数据库,则必须替换代码示例中的以下代码行:

conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _ sNWind & ";"

将此代码行替换为以下代码行:

conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _ sNWind & ";"

Excel 97 还提供 CopyFromRecordset 方法,但只能将其用于 DAO 记录集。 使用 Excel 97 的 CopyFromRecordset 不支持 ADO。

有关使用 ADO 和 CopyFromRecordset 方法的详细信息,请参阅 如何通过自动化将数据从 ADO 记录集传输到 Excel

使用自动化在工作表上创建 QueryTable

QueryTable 对象表示从外部数据源返回的数据生成的表。 自动执行 Microsoft Excel 时,只需向 OLEDB 或 ODBC 数据源提供连接字符串以及 SQL 字符串即可创建 QueryTable。 Excel 负责生成记录集并将其插入到指定位置的工作表中。 使用 QueryTables 比 CopyFromRecordset 方法具有几个优点:

  • Excel 处理记录集的创建及其在工作表中的位置。
  • 可以使用 QueryTable 保存查询,以便稍后可以刷新查询以获取更新的记录集。
  • 将新的 QueryTable 添加到工作表后,可以指定移动工作表上单元格中已存在的数据以容纳新数据 (请参阅 RefreshStyle 属性了解详细信息) 。

以下代码演示了如何自动执行 Excel 2000、Excel 2002 或 Office Excel 2003,以使用 Northwind 示例数据库中的数据在 Excel 工作表中创建新的 QueryTable:

'Create a new workbook in Excel    
Dim oExcel As Object    
Dim oBook As Object    
Dim oSheet As Object    
Set oExcel = CreateObject("Excel.Application")    
Set oBook = oExcel.Workbooks.Add    
Set oSheet = oBook.Worksheets(1)        

'Create the QueryTable    
Dim sNWind As String    
sNWind = _       
   "C:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb"    
Dim oQryTable As Object    
Set oQryTable = oSheet.QueryTables.Add( _    
"OLEDB;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _       
sNWind & ";", oSheet.Range("A1"), "Select * from Orders")    oQryTable.RefreshStyle = xlInsertEntireRows    
oQryTable.Refresh False        

'Save the Workbook and Quit Excel    
oBook.SaveAs "C:\Book1.xls"    
oExcel.Quit

使用剪贴板

Windows 剪贴板还可以用作将数据传输到工作表的机制。 若要将数据粘贴到工作表上的多个单元格中,可以复制一个字符串,其中列由制表符分隔,行由回车符分隔。 以下代码演示了 Visual Basic 如何使用其剪贴板对象将数据传输到 Excel:

'Copy a string to the clipboard    
Dim sData As String    
sData = "FirstName" & vbTab & "LastName" & vbTab & "Birthdate" & vbCr _            & "Bill" & vbTab & "Brown" & vbTab & "2/5/85" & vbCr _            
    & "Joe" & vbTab & "Thomas" & vbTab & "1/1/91"    
Clipboard.Clear     
Clipboard.SetText sData        

'Create a new workbook in Excel    
Dim oExcel As Object    
Dim oBook As Object    
Set oExcel = CreateObject("Excel.Application")    
Set oBook = oExcel.Workbooks.Add         

'Paste the data    
oBook.Worksheets(1).Range("A1").Select    
oBook.Worksheets(1).Paste        

'Save the Workbook and Quit Excel    
oBook.SaveAs "C:\Book1.xls"    
oExcel.Quit

创建 Excel 可以分析为行和列的带分隔符的文本文件

Excel 可以打开制表符或逗号分隔的文件,并将数据正确分析为单元格。 如果要将大量数据传输到工作表,同时使用很少的自动化(如果有的话),可以利用此功能。 对于客户端-服务器应用程序来说,这可能是一个很好的方法,因为可以在服务器端生成文本文件。 然后,可以在客户端使用适当的自动化打开文本文件。

以下代码演示如何从 ADO 记录集创建逗号分隔的文本文件:

'Create a Recordset from all the records in the Orders table    
Dim sNWind As String    
Dim conn As New ADODB.Connection   
Dim rs As ADODB.Recordset    
Dim sData As String    
sNWind = _       
   "C:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb"    conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _       sNWind & ";"    
conn.CursorLocation = adUseClient    
Set rs = conn.Execute("Orders", , adCmdTable)        

'Save the recordset as a tab-delimited file    
sData = rs.GetString(adClipString, , vbTab, vbCr, vbNullString)    
Open "C:\Test.txt" For Output As #1    
Print #1, sData    
Close #1         

'Close the connection    
rs.Close    
conn.Close        

'Open the new text file in Excel    
Shell "C:\Program Files\Microsoft Office\Office\Excel.exe " & _       Chr(34) & "C:\Test.txt" & Chr(34), vbMaximizedFocus

注意 如果使用 Office 2007 版本的 Northwind 数据库,则必须替换代码示例中的以下代码行:

conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _       
   sNWind & ";"

将此代码行替换为以下代码行:

conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _       
   sNWind & ";"

如果文本文件具有 .CSV 扩展名,Excel 将打开文件而不显示文本导入向导,并自动假定该文件是逗号分隔的。 同样,如果文件具有 .TXT 扩展名,Excel 会自动使用制表符分隔符分析文件。

在前面的代码示例中,Excel 是使用 Shell 语句启动的,文件的名称用作命令行参数。 上一个示例中未使用任何自动化。 但是,如果需要,可以使用最少量的自动化打开文本文件并将其保存为 Excel 工作簿格式:

'Create a new instance of Excel    
Dim oExcel As Object    
Dim oBook As Object    
Dim oSheet As Object    
Set oExcel = CreateObject("Excel.Application")            

'Open the text file   
 Set oBook = oExcel.Workbooks.Open("C:\Test.txt")        

'Save as Excel workbook and Quit Excel    
oBook.SaveAs "C:\Book1.xls", xlWorkbookNormal    
oExcel.Quit

使用 ADO 将数据传输到工作表

使用 Microsoft Jet OLE DB 提供程序,可以将记录添加到现有 Excel 工作簿中的表中。 Excel 中的“表”只是具有定义名称的区域。 范围的第一行必须包含标题 (或字段名称) ,所有后续行都包含记录。 以下步骤演示如何创建包含名为 MyTable 的空表的工作簿。

Excel 97、Excel 2000 和 Excel 2003
  1. 在 Excel 中启动新工作簿。

  2. 将以下标头添加到 Sheet1 的单元格 A1:B1:

    A1:FirstName B1:LastName

  3. 将单元格 B1 的格式设置为右对齐。

  4. 选择 A1:B1。

  5. 在“插入”菜单上,选择“名称”,然后选择“定义”。 输入名称“MyTable”,然后单击“确定”。

  6. 将新工作簿另存为 C:\Book1.xls 并退出 Excel。

若要使用 ADO 将记录添加到 MyTable,可以使用如下所示的代码:

'Create a new connection object for Book1.xls    
Dim conn As New ADODB.Connection    
conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _       
    "Data Source=C:\Book1.xls;Extended Properties=Excel 8.0;"    
conn.Execute "Insert into MyTable (FirstName, LastName)" & _       
   " values ('Bill', 'Brown')"    
conn.Execute "Insert into MyTable (FirstName, LastName)" & _       
   " values ('Joe', 'Thomas')"    
conn.Close
Excel 2007
  1. 在 Excel 2007 中,启动新工作簿。

  2. 将以下标头添加到 Sheet1 的单元格 A1:B1:

    A1:FirstName B1:LastName

  3. 将单元格 B1 的格式设置为右对齐。

  4. 选择 A1:B1。

  5. 在功能区上,单击“ 公式 ”选项卡,然后单击“ 定义名称”。 键入名称“MyTable”,然后单击“ 确定”。

  6. 将新工作簿另存为 C:\Book1.xlsx,然后退出 Excel。

若要使用 ADO 将记录添加到 MyTable 表,请使用类似于以下代码示例的代码。

'Create a new connection object for Book1.xls    
Dim conn As New ADODB.Connection    
conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _       
   "Data Source=C:\Book1.xlsx;Extended Properties=Excel 12.0;"    
conn.Execute "Insert into MyTable (FirstName, LastName)" & _       
   " values ('Scott', 'Brown')"    
conn.Execute "Insert into MyTable (FirstName, LastName)" & _       
   " values ('Jane', 'Dow')"    
conn.Close

以这种方式向表添加记录时,工作簿中的格式设置会保持。 在前面的示例中,添加到 B 列的新字段采用右对齐格式。 添加到行的每个记录都从其上方的行中借用格式。

应注意,将记录添加到工作表中的一个或多个单元格时,它会覆盖这些单元格中之前的任何数据;换句话说,添加新记录时,工作表中的行不会“向下推送”。 在设计工作表上的数据布局时,应牢记这一点。

注意

安装 Office 2003 Service Pack 2 (SP2) 之后,或者安装 Microsoft 知识库文章904018中包含的 Access 2002 更新之后,使用 ADO 或 DAO 更新 Excel 工作表中的数据的方法在 Access 内的 Visual Basic for Application 环境中不起作用。 此方法适用于其他 Office 应用程序的 Visual Basic for Application 环境,例如 Word、Excel 和 Outlook。

有关更多信息,请参阅下面的文章:

不能在 Office Access 2003 或 Access 2002 中更改、添加或删除链接到 Excel 工作簿的表中的数据

有关使用 ADO 访问 Excel 工作簿的详细信息,请参阅 如何使用 ADO 从 ASP 查询和更新 Excel 数据

使用 DDE 将数据传输到 Excel

DDE 是自动化的替代方法,作为与 Excel 通信和传输数据的方式;但是,随着自动化和 COM 的出现,DDE 不再是与其他应用程序通信的首选方法,并且仅应在没有其他解决方案可供你使用时使用。

若要使用 DDE 将数据传输到 Excel,可以使用 LinkPoke 方法将数据戳入特定单元格区域 () ,或者使用 LinkExecute 方法发送 Excel 将执行的命令。

下面的代码示例演示如何与 Excel 建立 DDE 对话,以便你可以将数据戳到工作表上的单元格并执行命令。 使用此示例,在 LinkTopic Excel 中成功建立 DDE 对话 |MyBook.xls,名称为 MyBook.xls 的工作簿必须在正在运行的 Excel 实例中打开。

注意

使用 Excel 2007 时,可以使用新的 .xlsx 文件格式来保存工作簿。 请确保更新以下代码示例中的文件名。 在此示例中,Text1 表示 Visual Basic 窗体上的文本框控件:

'Initiate a DDE communication with Excel    
Text1.LinkMode = 0    
Text1.LinkTopic = "Excel|MyBook.xls"    
Text1.LinkItem = "R1C1:R2C3"    
Text1.LinkMode = 1        

'Poke the text in Text1 to the R1C1:R2C3 in MyBook.xls    
Text1.Text = "one" & vbTab & "two" & vbTab & "three" & vbCr & _                             
             "four" & vbTab & "five" & vbTab & "six"    
Text1.LinkPoke        

'Execute commands to select cell A1 (same as R1C1) and change the font  format 
Text1.LinkExecute "[SELECT(""R1C1"")]"    
Text1.LinkExecute "[FONT.PROPERTIES(""Times New Roman"",""Bold"",10)]"        

'Terminate the DDE communication    
Text1.LinkMode = 0

将 LinkPoke 与 Excel 配合使用时,可以指定 LinkItem 的行列 (R1C1) 表示法的区域。 如果要将数据指向多个单元格,则可以使用字符串,其中列由制表符分隔,行由回车符分隔。

使用 LinkExecute 要求 Excel 执行命令时,必须按照 Excel 宏语言 (XLM) 语法为 Excel 提供命令。 XLM 文档未包含在 Excel 版本 97 及更高版本中。
建议不要使用 DDE 与 Excel 进行通信。 自动化提供了最大的灵活性,让你能够更好地访问 Excel 必须提供的新功能。