在VBScript中调用Excel工作表

我有以下代码:

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表单“Music”中的第1行和第195行之间打印两个随机单元格。 其中之一 – A列中的一个 – 代表专辑,另一个代表歌曲。 问题是需要相当长的时间来返回结果,大约20秒。

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

我认为Ansgar Wiechers的回答可能是正确的,即开始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) 

这里可能出现的一个问题是VBScript默认使用64位版本的wscript.exe来运行,而64位ACE.OLEDB只有在安装了64位版本的Office 2010或更高版本时才可用。 尽pipe如此,通过使用32位版本的wscript.exe运行脚本(例如,请参阅如何在64位机器上以32位模式运行VBScript? ),可以解决这个问题。

如果你决定走这条路线,并可以控制input的Excel文件,我build议在电子表格中添加一个标题行,并在连接string中将HDR=NO改为HDR=YES 。 这样,您可以在查询中按名称引用列(例如, SELECT TOP 1 album, song ... )而不是依赖“F1”语法。

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

  • 开始Excel和
  • 打开工作簿。

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

 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 

variablesquitExcel指示是否需要在脚本结尾处(当您创build新实例时)closuresExcel(当您使用已经运行的实例时)。

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

 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 

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

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

我刚刚在我5岁的笔记本电脑上运行脚本,并在2秒钟内得到答案。 Excel的一个实例是否已经打开在运行时间上没有什么区别。

(我在单元格A1中input“A1”,在单元格B1中input“B1”,然后将这些单元格拖到第195行以获得一组不错的唯一样本数据,从而创build了一个testingMusic.xlsx电子表格。

为什么不让Excel在运行时可见,这样您就可以亲自看到发生了什么事情?

例如,您可能会看到Excel需要一秒钟才能打开,而您所拥有的Excel加载项则需要十五秒才能初始化。 也有可能您的机器和/或硬盘驱动器很慢,确实需要20秒来运行。 谁知道…

为了得到一些见解,请使objApp.Visible = True并重新运行。

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

其他意见:1)您从.vbs脚本打开Excel与CreateObject的方法似乎是自动化Excel最可靠/可接受的方法。

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

3)我不习惯看到外部的VBS与Excel中的数据交互…我习惯于让VBS打开Excel.xlsm,然后让macros执行数字运算。 但是,macros指令带来了一个完全不同的麻烦。 我不是说你的方法好坏,只是不习惯这种方法。

祝你好运!