合并大型 excel 文件,无法绕过缓冲区溢出

Cosolidating large excel files, cant go around buffer overflow

我正在尝试使用以下代码将多个大型 excel 文件合并为一个文件

Sub Macro1()
    Application.DisplayAlerts = False
    Dim Country As String
    Dim i As Integer
    Dim j As Integer
    Dim k As Integer

    k = 2
    For i = 1 To 50
        Windows("Try2").Activate
        Country = Worksheets("Names").Cells(i, 1).Value
        Workbooks.Open Filename:= "C:path\" & Country & " "
        ActiveWorkbook.Sheets("Main").Activate
        finalrow = Cells(Rows.Count, 1).End(xlUp).Row

        Workbooks(Country).Sheets("Main").Range(Cells(1, 1), Cells(10000, 64)).Copy
        Workbooks("Try2").Sheets("Output").Activate
        Workbooks("Try2").Sheets("Output").Cells(k, 2).PasteSpecial xlPasteValues
        Range(Cells(k, 1), Cells(k + 10000, 1)) = Country
        finalrow2 = 10002 + k
        k = finalrow2 + 1
        Workbooks(Country).Sheets("Main").Activate
        Workbooks(Country).Close SaveChanges:=False
    Next i
End Sub

但是在合并 2-3 个文件后 excel 它抛出缓冲区溢出错误。我们有大约 50 个文件。我想弄清楚这是否只是 excel 无法处理大文件的问题,或者我的代码有问题。有什么方法可以引导 excel 处理更大的文件吗?

这里有几件事可能会导致您的宏失效。

首先,您将 ijk 声明为 'integer' 数据类型;问题在于整数可以容纳的最大可能值是 32,767。如果超出这个范围,就会出现缓冲区溢出。

其次,您声明的是您不使用的变量,而不是声明您确实使用的变量。据我所知,j 没有在代码中的任何地方使用,但是使用了 finalrowfinalrow2 但没有在任何地方声明。

我建议您用 long 数据类型(长整型)替换可能非常高的 integer 数据类型。您可能还想为整数使用更具描述性的名称,以使您的代码更易于阅读:

Dim iCycler as integer
Dim kStart as long
Dim FinalRow as Long
Dim FinalRow2 as Long

运行 看看你得到了什么。

编辑添加:

这里有一个适合您的完整流程:

Sub Duplicator()

    'Define the source file, sheet, and range
    Dim wbkSource As Workbook
    Dim shtSource As Worksheet
    Dim rngSource As Range
    'Define the target file, sheet and range
    Dim wbkTarget As Workbook
    Dim shtTarget As Worksheet
    Dim rngTarget As Range
    'Define the sheet with the list of countries
    Dim shtControl As Worksheet
    'Prepare control integers
    Dim iLoop As Integer
    Dim lLastRow As Long

    'Define the target file as the active workbook
    Set wbkTarget = ActiveWorkbook
    Set shtTarget = wbkSource.Sheets("Output")
    Set rngTarget = shtTarget.Range("A2")
    Set shtControl = wbkTarget.Sheets("Names")

    'Loop through the list
    For iLoop = 1 To 50
        'Open the source file and assign it to a variable.
        Set wbkSource = Workbooks.Open("C:\path\" & shtControl.Cells(iLoop, 1).Value)
        'Assign the source sheet
        Set shtSource = wbkSource.Sheets("Main")
        'Find the last row of data
        lLastRow = shtSource.Range("A" & Rows.Count).End(xlUp).Row
        'Use the last row to build a source range variable
        Set rngSource = shtSource.Range("A1", "BL" & lLastRow)
        'Check that there is space for the copy. If there is not, create a new sheet for the new data
        If rngTarget.Row + lLastRow > shtTarget.Rows.Count Then
            Set shtTarget = wbkTarget.Sheets.Add
            shtTarget.Name = "Output 2"
            Set rngTarget = shtTarget.Range("A2")
        End If
        'Use the size of rngSource to define the size of the target range
        Set rngTarget = rngTarget.Resize(rngSource.Rows.Count, rngSource.Columns.Count)
        'Duplicate the values over
        rngTarget.Value = rngSource.Value
        'Prepare the target range for the next loop
        Set rngTarget = shtTarget.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
        'Close the source file
        wbkSource.Close False
    Next iLoop
End Sub

通过在整个过程中声明和使用变量,代码应该更易于编写和阅读。它也应该 运行 更快,因为它使用 range1.value = range2.value 结构,它绕过了相当慢的剪贴板。它还包含一项检查,以确保您没有超过 1,048,576 行数据,否则会导致崩溃。

Werff 已经向您解释了良好的编码实践,您可以尝试其他(注释)代码:

Sub Macro1()
    Dim outputSht As Worksheet '<--| declare a variable to set your "output" sheet to
    Dim countryData As Variant, countryNames As Variant '<--| declare arrays to store "country names" and "country data" in
    Dim country As Variant '<-- "countries" looping variable

    Application.Calculation = xlCalculationManual '<-- disable calculations
    Application.ScreenUpdating = False '<-- disable screen updating


    With Workbooks("Try").Worksheets("Names") '<--| reference "country names" worksheet
        countryNames = Application.Transpose(.Range("A1", .Cells(.Rows.count, 1).End(xlUp)).Value) '<--| store country names in column "A" from row 1 down to last not empty row
    End With

    Set outputSht = Workbooks("Try").Worksheets("Output") '<--| set "output" worksheet
    For Each country In countryNames '<-- loop through countries stored in 'countryNames'

        With Workbooks.Open(FileName:="C:path\" & Country).Sheets("Main") '<--| open current country workbook and reference its "Main" sheet
            countryData = .Range("BL1", .Cells(.Rows.count, 1).End(xlUp)).Value '<--| store current country data in 'countryData' array
            .Parent.Close SaveChanges:=False '<--| close current country workbook
        End With

        With outputSht '<--| reference output sheet
            With .Cells(.Rows.count, 1).End(xlUp).Offset(1).Resize(UBound(countryData, 1)) '<--|reference its column A range from first empty cell after last not empty cell down to as many rows as current country array has
                .Value = country '<--| write current country name in referenced range
                .Offset(, 1).Resize(, 64).Value = countryData '<--| write country data array content from column B rightwards
            End With
        End With
    Next country

    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True

End Sub

由于它使用数组存储数据,因此它受到数组最大大小限制为 65536 行的限制。如果您的 "countries" 工作簿 "Main" 工作表的行数超过此限制,则必须采用不同的粘贴值技术(例如在范围值之间)