单元格中的宏写入速度慢 VBA
Slow VBA macro writing in cells
我有一个 VBA 宏,可以将数据写入已清除的工作表,但它真的很慢!
我正在从 Project Professional 实例化 Excel。
Set xlApp = New Excel.Application
xlApp.ScreenUpdating = False
Dim NewBook As Excel.WorkBook
Dim ws As Excel.Worksheet
Set NewBook = xlApp.Workbooks.Add()
With NewBook
.Title = "SomeData"
Set ws = NewBook.Worksheets.Add()
ws.Name = "SomeData"
End With
xlApp.Calculation = xlCalculationManual 'I am setting this to manual here
RowNumber=2
Some random foreach cycle
ws.Cells(RowNumber, 1).Value = some value
ws.Cells(RowNumber, 2).Value = some value
ws.Cells(RowNumber, 3).Value = some value
...............
ws.Cells(RowNumber, 12).Value = some value
RowNumber=RowNumber+1
Next
我的问题是,foreach 循环有点大。最后,我将获得大约 29000 行。在一台相当不错的电脑上完成这个需要超过 25 分钟。
有什么技巧可以加快写入单元格的速度吗?
我做了以下事情:
xlApp.ScreenUpdating = False
xlApp.Calculation = xlCalculationManual
我是否以错误的方式引用了单元格?是否有可能写成一整行,而不是单个单元格?
这样会更快吗?
我已经测试了我的代码,foreach 循环非常快(我将值写入一些随机变量),所以我知道,写入单元格是占用所有时间的。
如果您需要更多信息,代码片段请告诉我。
感谢您的宝贵时间。
这样做:
ws.Range(Cells(1, RowNumber), Cells(12, Number))=arr
其中 arr 是您的 some value
值的数组,例如
Dim arr(1 to 100) as Long
或者如果可能(甚至更快):
ws.Range(Cells(firstRow, RowNumber), Cells(lastRow, Number))=twoDimensionalArray
其中 twoDimensionalArray
是 some value
值的二维数组,例如
Dim twoDimensionalArray(1 to [your last row], 1 to 12) as Long
Would it be possible, to write in a whole row, instead of the single cells?
Would that be faster?
是的,是的。这正是您可以提高性能的地方。 Reading/writing 到单元格是出了名的慢。您有多少个单元格reading/writing 并不重要,重要的是您为此对 COM 对象进行了多少次调用。因此,使用二维数组以块的形式读取和写入数据。
这是将 MS Project 任务数据写入 Excel 的示例过程。我模拟了一个包含 29,000 个任务的时间表,它会在几秒钟内运行。
Sub WriteTaskDataToExcel()
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
xlApp.Visible = True
Dim NewBook As Excel.Workbook
Dim ws As Excel.Worksheet
Set NewBook = xlApp.Workbooks.Add()
With NewBook
.Title = "SomeData"
Set ws = NewBook.Worksheets.Add()
ws.Name = "SomeData"
End With
xlApp.ScreenUpdating = False
Dim OrigCalc As Excel.XlCalculation
OrigCalc = xlApp.Calculation
xlApp.Calculation = xlCalculationManual
Const BlockSize As Long = 1000
Dim Values() As Variant
ReDim Values(BlockSize, 12)
Dim idx As Long
idx = -1
Dim RowNumber As Long
RowNumber = 2
Dim tsk As Task
For Each tsk In ActiveProject.Tasks
idx = idx + 1
Values(idx, 0) = tsk.ID
Values(idx, 1) = tsk.Name
' populate the rest of the values
Values(idx, 11) = tsk.ResourceNames
If idx = BlockSize - 1 Then
With ws
.Range(.Cells(RowNumber, 1), .Cells(RowNumber + BlockSize - 1, 12)).Value = Values
End With
idx = -1
ReDim Values(BlockSize, 12)
RowNumber = RowNumber + BlockSize
End If
Next
' write last block
With ws
.Range(.Cells(RowNumber, 1), .Cells(RowNumber + BlockSize - 1, 12)).Value = Values
End With
xlApp.ScreenUpdating = True
xlApp.Calculation = OrigCalc
End Sub
我当时的情况是我正在填充大量 table,我不得不逐个单元格,然后逐行。痛苦地缓慢。我仍然不确定为什么,但在循环之前我添加了:
cells(1,1).select
(如果这很重要,那是我 table 外面的单元格 -idk)并且速度 显着 提高了。我的意思是从 10 分钟到大约 30 秒。因此,如果您要写入 table 中的单元格,请尝试一下。
我应该补充一点,我总是做的第一件事就是禁用事件、屏幕更新和切换到手动计算。在我尝试此解决方法之前,这没有帮助
之前的回答提到做 cells(1,1).select
。
我的建议是在更新循环之前执行 Worksheets("Sheet2").Activate
。
将上面的 Sheet2
替换为任何未更新单元格的 sheet。这带来了真正实质性的改进。
即使您可以将应用程序 displayupdating 设置为 false,更改激活的 sheet 确实可以消除开销。
我有一个 VBA 宏,可以将数据写入已清除的工作表,但它真的很慢!
我正在从 Project Professional 实例化 Excel。
Set xlApp = New Excel.Application
xlApp.ScreenUpdating = False
Dim NewBook As Excel.WorkBook
Dim ws As Excel.Worksheet
Set NewBook = xlApp.Workbooks.Add()
With NewBook
.Title = "SomeData"
Set ws = NewBook.Worksheets.Add()
ws.Name = "SomeData"
End With
xlApp.Calculation = xlCalculationManual 'I am setting this to manual here
RowNumber=2
Some random foreach cycle
ws.Cells(RowNumber, 1).Value = some value
ws.Cells(RowNumber, 2).Value = some value
ws.Cells(RowNumber, 3).Value = some value
...............
ws.Cells(RowNumber, 12).Value = some value
RowNumber=RowNumber+1
Next
我的问题是,foreach 循环有点大。最后,我将获得大约 29000 行。在一台相当不错的电脑上完成这个需要超过 25 分钟。
有什么技巧可以加快写入单元格的速度吗? 我做了以下事情:
xlApp.ScreenUpdating = False
xlApp.Calculation = xlCalculationManual
我是否以错误的方式引用了单元格?是否有可能写成一整行,而不是单个单元格?
这样会更快吗?
我已经测试了我的代码,foreach 循环非常快(我将值写入一些随机变量),所以我知道,写入单元格是占用所有时间的。
如果您需要更多信息,代码片段请告诉我。
感谢您的宝贵时间。
这样做:
ws.Range(Cells(1, RowNumber), Cells(12, Number))=arr
其中 arr 是您的 some value
值的数组,例如
Dim arr(1 to 100) as Long
或者如果可能(甚至更快):
ws.Range(Cells(firstRow, RowNumber), Cells(lastRow, Number))=twoDimensionalArray
其中 twoDimensionalArray
是 some value
值的二维数组,例如
Dim twoDimensionalArray(1 to [your last row], 1 to 12) as Long
Would it be possible, to write in a whole row, instead of the single cells? Would that be faster?
是的,是的。这正是您可以提高性能的地方。 Reading/writing 到单元格是出了名的慢。您有多少个单元格reading/writing 并不重要,重要的是您为此对 COM 对象进行了多少次调用。因此,使用二维数组以块的形式读取和写入数据。
这是将 MS Project 任务数据写入 Excel 的示例过程。我模拟了一个包含 29,000 个任务的时间表,它会在几秒钟内运行。
Sub WriteTaskDataToExcel()
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
xlApp.Visible = True
Dim NewBook As Excel.Workbook
Dim ws As Excel.Worksheet
Set NewBook = xlApp.Workbooks.Add()
With NewBook
.Title = "SomeData"
Set ws = NewBook.Worksheets.Add()
ws.Name = "SomeData"
End With
xlApp.ScreenUpdating = False
Dim OrigCalc As Excel.XlCalculation
OrigCalc = xlApp.Calculation
xlApp.Calculation = xlCalculationManual
Const BlockSize As Long = 1000
Dim Values() As Variant
ReDim Values(BlockSize, 12)
Dim idx As Long
idx = -1
Dim RowNumber As Long
RowNumber = 2
Dim tsk As Task
For Each tsk In ActiveProject.Tasks
idx = idx + 1
Values(idx, 0) = tsk.ID
Values(idx, 1) = tsk.Name
' populate the rest of the values
Values(idx, 11) = tsk.ResourceNames
If idx = BlockSize - 1 Then
With ws
.Range(.Cells(RowNumber, 1), .Cells(RowNumber + BlockSize - 1, 12)).Value = Values
End With
idx = -1
ReDim Values(BlockSize, 12)
RowNumber = RowNumber + BlockSize
End If
Next
' write last block
With ws
.Range(.Cells(RowNumber, 1), .Cells(RowNumber + BlockSize - 1, 12)).Value = Values
End With
xlApp.ScreenUpdating = True
xlApp.Calculation = OrigCalc
End Sub
我当时的情况是我正在填充大量 table,我不得不逐个单元格,然后逐行。痛苦地缓慢。我仍然不确定为什么,但在循环之前我添加了:
cells(1,1).select
(如果这很重要,那是我 table 外面的单元格 -idk)并且速度 显着 提高了。我的意思是从 10 分钟到大约 30 秒。因此,如果您要写入 table 中的单元格,请尝试一下。
我应该补充一点,我总是做的第一件事就是禁用事件、屏幕更新和切换到手动计算。在我尝试此解决方法之前,这没有帮助
之前的回答提到做 cells(1,1).select
。
我的建议是在更新循环之前执行 Worksheets("Sheet2").Activate
。
将上面的
Sheet2
替换为任何未更新单元格的 sheet。这带来了真正实质性的改进。即使您可以将应用程序 displayupdating 设置为 false,更改激活的 sheet 确实可以消除开销。