[英]Excel VBA: Opening Workbooks and Copying Cells
The macro below opens a series of workbooks from a list, then copies some data from them. 下面的宏从列表中打开一系列工作簿,然后从中复制一些数据。 It works fine for the first workbook, then crashes on the second.
它在第一个工作簿上正常工作,然后在第二个工作簿上崩溃。 I've tried changing the order, and it's always the second workbook that causes it to crash.
我尝试过更改顺序,它始终是导致其崩溃的第二个工作簿。
Sub ImportData()
Dim lastRow As Long
Dim lastSumRow As Long
Dim j As Long
Dim k As Long
With ActiveSheet
lastRow = ActiveSheet.Cells(1048576, 1).End(xlUp).Row
End With
For k = 2 To lastRow
k = 2
lastUsedRow = ThisWorkbook.Sheets("Summary").Cells(1048576, 1).End(xlUp).Row
If ActiveSheet.Cells(k, 2).Value <> "Imported" Then
Workbooks.Open Filename:=ThisWorkbook.Path & "\Analysis\" & Cells(k, 1), UpdateLinks:=False
ActiveWorkbook.Sheets("Summary").Activate
For j = 3 To 100
If j Mod 3 = 0 Then
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 1).Value = ActiveWorkbook.Sheets("Summary").Cells(j, 1).Value
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 2).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 1, 2).Value
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 3).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 1, 3).Value
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 4).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 1, 4).Value
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 5).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 2, 2).Value
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 6).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 2, 3).Value
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 7).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 2, 4).Value
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 8).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 1, 5).Value
End If
Next j
ActiveWorkbook.Close
End If
ThisWorkbook.Sheets("Setup").Cells(k, 2).Value = "Imported"
Next k
End Sub
I'm guessing your error is here: 我猜你的错误在这里:
Workbooks.Open Filename:=ThisWorkbook.Path & "\\Analysis\\" & Cells(k, 1), UpdateLinks:=False 'Ooops ^^^^^
The .Activate
and .Select
calls are convoluted enough that I'm not really going to expend the effort figuring out what should be the active worksheet at that particular point in your code on the second run through the loop. 该
.Activate
和.Select
呼叫进行卷积足够,我不是真的要花费精力搞清楚什么应该是在你的代码通过循环第二次运行特定点活动工作表。 Whatever it is, it's different than it was when you started and an unqualified call to Cells
implicitly refers to whatever worksheet is the ActiveSheet
at the time. 不管它是什么,它都与您开始时不同,并且对
Cells
的无条件调用隐式地引用了当时是ActiveSheet
任何工作表。 This builds a bad file name (or fails completely) and then the wheels come off. 这将生成错误的文件名(或完全失败),然后滚轮脱落。
The best thing to do is not use the Active*
objects at all. 最好的办法是根本不使用
Active*
对象。 Get references to the objects that you're using, and well, use them. 获取对您正在使用的对象的引用,然后使用它们。 That way there is no chance that you'll get wires crossed.
这样,您就不会有电线交叉的可能性。 While you're at it, you can give them names that make it obvious what you're working with at a glance.
在查看时,您可以给他们命名,使您一眼就能清楚地看到正在使用的内容。
Couple other things before we get to the code that doesn't use Activate
and Select
. 在获得不使用
Activate
和Select
的代码之前,请结合其他因素。
lastSumRow
is never used and lastUsedRow
is never declared. lastSumRow
是从来没有使用过lastUsedRow
从未声明。 I'm assuming they were supposed to be the same thing. 我假设他们应该是同一回事。 You should put
Option Explicit
at the top of your modules to avoid this type of error (and worse ones). 您应该将
Option Explicit
放在模块的顶部,以避免此类错误(甚至更糟)。
These 2 lines of code make very little sense together: 这两行代码在一起几乎没有什么意义:
For j = 3 To 100 If j Mod 3 = 0 Then
If you only want to copy every 3rd row, skip all the division and just increment your loop counter with a Step
of 3: 如果您只想复制每第3行,请跳过所有除法,仅以3
Step
递增循环计数器:
For j = 3 To 99 Step 3
Note that you can stop at 99, because 100 Mod 3
is never going to be 0
. 请注意,您可以在99处停止,因为
100 Mod 3
永远不会为0
。
Your With
block here isn't using the captured reference... 您的
With
块此处未使用捕获的参考...
With ActiveSheet lastRow = ActiveSheet.Cells(1048576, 1).End(xlUp).Row End With
...but you continually use this pattern that would be useful in a With
block: ...但是您一直使用在
With
块中有用的这种模式:
ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 1).Value = ... ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 2).Value = ... ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 3).Value = ...
Hard-coding Cells(1048576, 1)
will fail on older versions of Excel. 硬编码
Cells(1048576, 1)
在旧版本的Excel上将失败。 You should use Rows.Count instead. 您应该改用Rows.Count。
As mentioned in the comments, k = 2
creates an infinite loop. 如评论中所述,
k = 2
创建一个无限循环。
You don't need to repeatedly find the last row of the sheet you're copying to with this code: 您无需使用以下代码重复查找要复制到的工作表的最后一行:
lastUsedRow = ThisWorkbook.Sheets("Summary").Cells(1048576, 1).End(xlUp).Row
Each time you go through your " j
" loop, the last row increases by one. 每次您执行“
j
”循环时,最后一行将增加一。 Just add 1 to lastUsedRow
instead of doing all the row counting gymnastics. 只需将1加到
lastUsedRow
而不是对所有的体操进行计数。
If you're working with Worksheets
, use the Worksheets
collection instead of the Sheets
collection: 如果您正在使用
Worksheets
,请使用Worksheets
集合而不是Sheets
集合:
ThisWorkbook.Sheets("Summary") '<--I could return a Chart!
Put all of that together, and you come up with something like the code below. 将所有这些放在一起,您将得到类似于以下代码的内容。 Note that I have no clue what the
ActiveSheet
is supposed to be when you start this macro, so I just named the variable it's stored in active
. 请注意,当您启动此宏时,我不知道
ActiveSheet
应该是什么,因此我只是将其命名为存储在active
的变量。 It's quite possible that it's one of the other worksheets it grabs a reference too (I have no clue) - if so, you should consolidate them into one reference: 它很可能也是它也获得参考的其他工作表之一(我不知道)-如果是这样,您应该将它们合并为一个参考:
Public Sub ImportData()
Dim lastRow As Long
Dim lastUsedRow As Long
Dim dataRow As Long
Dim fileNameRow As Long
Dim active As Worksheet
Set active = ActiveSheet
With active
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
Dim setupSheet As Worksheet
Set setupSheet = ThisWorkbook.Worksheets("Setup")
With ThisWorkbook.Worksheets("Summary")
lastUsedRow = .Cells(.Rows.Count, 1).End(xlUp).Row
For fileNameRow = 2 To lastRow
If active.Cells(fileNameRow, 2).Value <> "Imported" Then
Dim source As Workbook
Set source = Workbooks.Open(ThisWorkbook.Path & "\Analysis\" & _
active.Cells(fileNameRow, 1), False)
Dim dataSheet As Worksheet
Set dataSheet = source.Worksheets("Summary")
For dataRow = 3 To 99 Step 3
.Cells(lastUsedRow, 1).Value = dataSheet.Cells(dataRow, 1).Value
.Cells(lastUsedRow, 2).Value = dataSheet.Cells(dataRow + 1, 2).Value
.Cells(lastUsedRow, 3).Value = dataSheet.Cells(dataRow + 1, 3).Value
.Cells(lastUsedRow, 4).Value = dataSheet.Cells(dataRow + 1, 4).Value
.Cells(lastUsedRow, 5).Value = dataSheet.Cells(dataRow + 2, 2).Value
.Cells(lastUsedRow, 6).Value = dataSheet.Cells(dataRow + 2, 3).Value
.Cells(lastUsedRow, 7).Value = dataSheet.Cells(dataRow + 2, 4).Value
.Cells(lastUsedRow, 8).Value = dataSheet.Cells(dataRow + 1, 5).Value
lastUsedRow = lastUsedRow + 1
Next
source.Close
End If
setupSheet.Cells(fileNameRow, 2).Value = "Imported"
Next
End With
End Sub
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.