【问题标题】:Why is writing Excel cell values fast in VBScript but slow in PowerShell?为什么在 VBScript 中写入 Excel 单元格值很快,而在 PowerShell 中却很慢?
【发布时间】:2012-10-06 18:14:18
【问题描述】:

为什么在 VBScript 中将单元格值写入 Excel 比在 PowerShell 中快得多? PowerShell 不是新事物,VBScript 不是已弃用的 MS 脚本语言吗?

VBScript 示例(保存到文件名.vbs) 这会在瞬间运行。

Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = false
Set objWorkbook = objExcel.Workbooks.Add()

' Edit: increased number of writes to 500 to make speed difference more noticeable
For row = 1 To 500
     'Edit: using .cells(row,1) instead of .cells(50,1) - this was a mistake
     objWorkbook.workSheets(1).cells(row,1).value = "test"
Next

objWorkbook.SaveAs(CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName) & "\test.xlsx")
objExcel.Quit
msgbox "Done."

PowerShell 示例(保存到 filename.ps1) 这需要几秒钟才能运行(数千条记录有问题)

#need this to work around bug if you use a non-US locale: http://support.microsoft.com/default.aspx?scid=kb;en-us;320369
[System.Threading.Thread]::CurrentThread.CurrentCulture = "en-US" 

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $False
$xls_workbook = $excel.Workbooks.Add()

# Edit: using foreach instead of for
# Edit: increased number of writes to 500 to make speed difference more noticeable
foreach ($row in 1..500) {
    # Edit: Commented out print-line, slows down the script
    #"Row " + $row
    # This is very slow! - http://forums.redmondmag.com/forums/forum_posts.asp?tid=4037&pn=7
    $xls_workbook.sheets.item(1).cells.item($row,1) = "test"
}

$xls_workbook.SaveAs($MyInvocation.MyCommand.Definition.Replace($MyInvocation.MyCommand.Name, "") + "test.xlsx")
$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)

我想将它用于数千条记录。如果没有快速的方法来做到这一点,PowerShell 不是一个选项。有更好的选择吗?

【问题讨论】:

标签: excel optimization powershell vbscript powershell-2.0


【解决方案1】:

有些东西在这里没有加起来:

您的 VBScript 一遍又一遍地写入一个单元格,而您的 PowerShell 代码写入 100 个单元格

objWorkbook.workSheets(1).cells(50,1).value = "test"

$xls_workbook.sheets.item(1).cells.item($row,1) = "test"

您正在 PowerShell 上执行 "Row " + $row - 这也可能会抵消比较。

如果你想写入多个单元格,你应该考虑使用数组并写入整个范围,因为这样有更好的性能。

【讨论】:

  • 我没有运行 VBScript 版本,但有 100 条记录,"Row " + $row 输出增加了大约半秒(对我来说总运行时间不到 5 秒)。
  • 您应该正确运行 VBScript 版本 - 填充单个单元格也是 VB 下的性能杀手 - 在我的机器上这大约需要一秒钟 - 没有保存部分(i7@3,4GHz 8GB Ram)。
  • 运行更正后的 VBS(使用 row 而不是 50),我得到了 1.391 秒 - 比 PowerShell 版本快 3 倍。
  • 嘿 Jook,对不起, (50, 1) 是一个错误,它确实必须是 ($row, 1)。我还将行数增加到 500 以使速度差异更加明显。在我的系统上,使用当前脚本,VBS 在大约一秒内完成,PS 在 20 秒内完成。对于 10.000 行,vbs 在 9 秒内完成。我不想知道 PS 需要多长时间...
  • 现在是一些结果 ;) 很抱歉,我对 PS 了解不多,无法进一步帮助您;不过,为您的问题 +1,因为您让我对这个问题的解决方案非常感兴趣。
【解决方案2】:

您可以通过消除 for 循环测试并使用 foreach 来缩短 PowerShell 版本的时间。

for ($row = 1; $row -le 100; $row++)

前往:

foreach ($row in 1..100)

这样做可以消除比较和增量。

但除此之外,我的观察结果与您的一致(请参阅我对 Jook 的回答的 cmets)。

【讨论】:

  • 感谢您的提示。然而,这似乎只是微小的速度提升(如果有的话)。
  • 已经一次又一次地证明 for 比 foreach 快。我敢肯定这在powershell中没有什么不同......所以它的速度会略微下降......
【解决方案3】:

您可以通过不遍历单个单元格来加快速度:

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $True
$xls_workbook = $excel.Workbooks.Add()

$range = $xls_workbook.sheets.item(1).Range("A1:A100")
$range.Value2 = "test"

如果您想将值数组写入范围,这里有一篇很好的博客文章,演示了类似的技术:

How to Get Data into an Excel Spreadsheet Very Quickly with PowerShell

【讨论】:

  • 好吧,我猜到 Array-Attempt 的链接是解决方案,但我真的很想知道,与 VB 中的数组解决方案相比,PS 是否更快。 @Wouter - 如果您能发布一些新的比较结果,那就太好了。
  • 虽然不是问题的真正答案,但我会将其标记为已接受的答案。它完成了我想做的事情;从 PowerShell 快速写入 Excel。我将假设在 PowerShell 中以某种方式逐个单元格地编写“不是这样做的方式”,而它在 VBScript 中工作。这似乎是 PowerShell 与 VBScript 可用性的倒退。如果有人对速度差异有解释,请随时告诉我!
  • @Jook - 我已经在 PS 和 VBS 中测试了 Range-method 最多 1.000.000 次写入,在这两种情况下都需要大约 3 秒,所以时间差(如果有的话)可以忽略不计.此外,它表明 Range 方法也是在 VBScript 中使用的更好方法,因为使用 Cell 方法需要很长时间。
【解决方案4】:

您仍然通过 COM 与 Excel 交互。由于 COMInterop 处理,这增加了一些开销。

【讨论】:

  • VBScript 不是也在使用 COM 对象吗?
【解决方案5】:

PowerShell,就其对 cmdlet 的设计和使用而言,是一个非标准的混乱,至少对于基本的东西。任何程序员都应该能够使用和理解的 VBScript 具有执行基本操作的通用方法,不需要安装特殊的 cmdlet 或将其包含在部署的代码中。我相信这在很多方面都是一种倒退。

在有人贬低我说我只是不使用 PowerShell 之前,我必须提一下,我在 UNIX shell 脚本编写方面有着悠久的历史。 PowerShell 显然是类似的,但对我来说,它的实现几乎没有那么好。

我确实知道现实决定了我迟早会使用 PowerShell - 我只是希望它在未来演变成更“标准”的替代品。

【讨论】:

  • 很公平。早在 1980 年代后期,我就编写了一些 UNIX shell 脚本,因此我很欣赏您的观点。
猜你喜欢
  • 2012-07-12
  • 1970-01-01
  • 2020-04-05
  • 2016-12-30
  • 1970-01-01
  • 2023-01-09
  • 2021-08-19
  • 2020-10-21
  • 2017-06-24
相关资源
最近更新 更多