我有以下代码:
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秒。
我想知道是否有更有效的方法可以用来更快地得到结果。
答案 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实例,而不是一直创建一个新实例:
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带来了一系列令人头疼的问题。我并不是说你的方法好或坏......只是不习惯那种方法。
祝你好运!