在VBScript中调用Excel工作表

时间:2014-03-09 07:06:35

标签: excel vbscript

我有以下代码:

Option Explicit
Randomize
Dim a, song, album
a = Int((Rnd*195)+1)
song = "B" & a
album = "A" & a

Dim objApp, objWbs, objWorkbook, objSheet

Set objApp = CreateObject("Excel.Application")
Set objWbs = objApp.WorkBooks
objApp.Visible = False
Set objWorkbook = objWbs.Open("C:\Users\Name\Documents\Music.xlsx")
Set objSheet = objWorkbook.Sheets("Sheet1")

song = objSheet.Range(song).Value 
album = objSheet.Range(album).Value

objWorkbook.Close False
objWbs.Close 
objApp.Quit 

Set objSheet = Nothing
Set objWorkbook = Nothing
Set objWbs = Nothing
Set objApp = Nothing

MsgBox("Album name: " & album & vbNewLine & "Song name: " & song)

它在Excel工作表"音乐"中打印第1行和第195行之间的两个随机单元格。其中一个 - A列中的一个 - 代表专辑,另一个代表歌曲。问题是返回结果需要相当长的时间,大约20秒。

我想知道是否有更有效的方法可以用来更快地得到结果。

3 个答案:

答案 0 :(得分:1)

我认为Ansgar Wiechers' answer可能是正确的,启动Excel是脚本中最慢的部分。您可以尝试使用ADO连接到Excel文件,就像它是一个数据库一样。这样可以避免启动Excel:

Option Explicit

Randomize
Dim conn, rst, song, album

Set conn = CreateObject("ADODB.Connection")
conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
    "Data Source=C:\Users\Name\Documents\Music.xlsx;" & _
    "Extended Properties='Excel 12.0 Xml;HDR=NO';"

' Select a random record; reference https://stackoverflow.com/a/9937263/249624
' Asc(album) is just a way to get some numeric value from the existing data
Set rst = conn.Execute("SELECT TOP 1 F1 AS album, F2 as song FROM [Sheet1$] ORDER BY Rnd(-(100000*Asc(F1))*Time())")

If rst.EOF Then
    song = "[NO RECORDS]"
    album = "[NO RECORDS]"
Else
    song = rst("song").Value
    album = rst("album").Value
End If

MsgBox("Album name: " & album & vbNewLine & "Song name: " & song)

这里可能存在的一个障碍是默认情况下使用64位版本的wscript.exe运行VBScript,而64位ACE.OLEDB仅在安装了64位版本的Office 2010或更高版本时才可用。但是,这可以通过使用32位版本的wscript.exe运行脚本来解决(例如,请参阅How do I run a VBScript in 32-bit mode on a 64-bit machine?)。

如果您决定使用此路线并可以控制输入的Excel文件,我建议您在电子表格中添加标题行,并在连接字符串中将HDR=NO更改为HDR=YES。这样,您可以在查询中按名称引用列(例如SELECT TOP 1 album, song ...),而不是依赖于“F1”语法。

答案 1 :(得分:0)

脚本中最耗时的步骤很可能是

  • 启动Excel和
  • 打开工作簿。

您可以做的一件事是使用已经运行的Excel实例,而不是一直创建一个新实例:

quitExcel = False

On Error Resume Next
Set objApp = GetObject(, "Excel.Application")
If Err Then
  Set objApp = CreateObject(, "Excel.Application")
  quitExcel  = True
End If
On Error Goto 0

变量quitExcel表示您是否需要在脚本结束时(当您创建新实例时)关闭Excel(当您使用已经运行的实例时)。

您还可以检查工作簿是否已打开:

wbOpen = False
For Each wb In objWbs
  If wb.Name = "Music.xlsx" Then
    Set objWorkbook = wb
    wbOpen = True
    Exit For
  End If
Next

If Not wbOpen Then
  Set objWorkbook = objWbs.Open("C:\Users\Name\Documents\Music.xlsx")
End If

除此之外,您唯一的选择是改变数据的存储方式或购买更快的硬件,AFAICS。

答案 2 :(得分:0)

Cheran,我不同意这里的答案。

我刚刚在我5岁的笔记本电脑上运行了你的脚本,并在大约2秒内得到了答案。 Excel的实例是否已经打开在运行时没有区别。

(我创建了一个测试Music.xlsx电子表格,输入" A1"在单元格A1中," B1"在单元格B1中,然后将这些单元格拖到第195行以获得一套很好的独特样本数据。)

为什么不让Excel在运行时可见,以便您可以自己查看正在发生的事情?

例如,您可能会看到Excel需要一秒钟才能打开,而您使用的Excel加载项需要另外十五秒才能初始化。您的机器和/或硬盘驱动器速度很慢,并且确实需要20秒才能运行它。谁知道......

要获得一些见解,请将objApp.Visible = True并重新运行。

除了MsgBox行之外,您还可以注释掉最后的八行,以便在脚本完成后您的Excel文件保持打开状态,这样您就可以看到其他线索。

其他观察: 1)从.vbs脚本中使用CreateObject打开Excel的方法似乎是自动化Excel的最可靠/可接受的方法。

2)此处未说明您如何运行.vbs脚本(命令行与从资源管理器双击)。您的脚本正在运行,但请注意,当人们尝试自动执行此操作时,使用cscript.exe运行.vbs也很常见。

3)我不习惯看到外部vbs与Excel内部的数据交互...我曾经习惯让vbs打开Excel.xlsm,然后让宏执行数字处理。但是,Macros带来了一系列令人头疼的问题。我并不是说你的方法好或坏......只是不习惯那种方法。

祝你好运!