5

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

VBScript 示例(保存到 filename.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 不是一个选项。有更好的选择吗?

4

5 回答 5

9

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

$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"

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

如何使用 PowerShell 快速将数据导入 Excel 电子表格

于 2012-10-16T19:14:29.463 回答
4

有些事情在这里没有加起来:

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

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

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

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

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

于 2012-10-16T15:51:32.363 回答
1

通过消除for循环测试并使用foreach.

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

去:

foreach ($row in 1..100)

通过这样做,您消除了比较和增量。

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

于 2012-10-16T16:20:29.143 回答
0

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

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

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

于 2013-04-20T23:58:51.800 回答
0

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

于 2012-11-22T02:26:25.607 回答