简体   繁体   English

根据文件名将多个 Excel 工作簿组合成单独的 Excel 工作簿 - VBA

[英]Combine multiple Excel workbooks into individual Excel workbooks based on filenames - VBA

I have multiple workbooks saved in C:\Temp.我有多个工作簿保存在 C:\Temp 中。

They look like:他们看起来像:

  • AAAA_1.xlsx AAAA_1.xlsx
  • AAAA_2.xlsx AAAA_2.xlsx
  • AAAA_3.xlsx AAAA_3.xlsx
  • BBBB_1.xksx BBBB_1.xksx
  • BBBB_2.xksx BBBB_2.xksx
  • CCCC_1.xlsx CCCC_1.xlsx
  • CCCC_2.xlsx CCCC_2.xlsx
  • CCCC_3.xlsx CCCC_3.xlsx
  • CCCC_4.xlsx CCCC_4.xlsx
  • etc.等等

I want to combine these files into master workbooks, so in the above example, I would have master file AAAA with data from AAAA_1, AAAA_2 and AAAA_3, a master file BBBB with data from BBBB_1 and BBBB_2, etc.我想将这些文件合并到主工作簿中,因此在上面的示例中,我将拥有包含来自 AAAA_1、AAAA_2 和 AAAA_3 的数据的主文件 AAAA,包含来自 BBBB_1 和 BBBB_2 的数据的主文件 BBBB 等。

Below is my current VBA.下面是我目前的 VBA。 I am able to search for prefix "AAAA" and that creates a new master file with all tabs from AAAA_1, AAAA_2 and AAAA_3, but then how to I start over (automatically) and create master files for all of the other prefixes that exist in C:\Temp?我能够搜索前缀“AAAA”并创建一个新的主文件,其中包含来自 AAAA_1、AAAA_2 和 AAAA_3 的所有选项卡,但是然后我如何(自动)重新开始并为存在的所有其他前缀创建主文件C:\温度? Thanks from a VBA rookie!感谢 VBA 菜鸟!

Sub Merge()
Path = "C:\Temp\"
Filename = Dir(Path & "AAAA" & "*.xlsx")
Do While Filename <> ""
Workbooks.Open Filename:=Path & Filename, ReadOnly:=True
 For Each Sheet In ActiveWorkbook.Sheets
   Sheet.Copy After:=ThisWorkbook.Sheets(1)
Next Sheet
 Application.DisplayAlerts = False
 Workbooks(Filename).Close
 Filename = Dir()
'Save workbook
Loop
 Application.DisplayAlerts = True
 
ActiveWorkbook.SaveAs Filename:="C:\Temp\File_" & Range("A1") & ".xlsx", FileFormat:= _
xlOpenXMLWorkbook, CreateBackup:=False
End Sub

Using a dictionary and collections.使用字典和 collections。 Scans the directory to compile a list of master workbooks first and then uses the collections to open and copy the sheets.扫描目录先编译主工作簿列表,然后使用 collections 打开和复制工作表。

Option Explicit

Sub consolidate()

    Const FOLDER = "C:\Temp\"

    Const SEP_COUNT = 0 'set to 0 to use fixed width
    Const SEP = "_"
    Const FIXED_WIDTH = 3 '
   
    Dim wb As Workbook, wbMaster As Workbook, ws As Worksheet
    Dim dict As Object, k, c As Collection, ar, f
    Dim m As Integer, n As Integer
    Dim sFile As String, s As String
    Set dict = CreateObject("Scripting.Dictionary")
    
    ' build collections
    sFile = Dir(FOLDER & "*.xlsx")
    Do While Len(sFile) > 0
        k = ""
       
        ' avoid masters
        If sFile Like "Master*" Then
            ' do nothing
        ElseIf SEP_COUNT > 0 Then
            If InStr(sFile, SEP) > 0 Then
                ' example INV_1104092_05_31_2021_000.xlsx
                ar = Split(sFile, SEP, SEP_COUNT + 1)
                If UBound(ar) >= SEP_COUNT Then
                     k = ar(0)
                     For n = 1 To SEP_COUNT - 1
                         k = k & "_" & ar(n)
                     Next
                End If
             End If
        ElseIf FIXED_WIDTH > 0 Then
            k = Left(sFile, FIXED_WIDTH)
        End If

        If Len(k) > 0 Then
            If Not dict.exists(k) Then
                dict.Add k, New Collection
            End If
            Set c = dict.Item(k)
            c.Add Trim(sFile), CStr(c.Count + 1)
        End If

        sFile = Dir
    Loop

    ' copy sheets
    Application.ScreenUpdating = False
    For Each k In dict
        ' create new master
        Set wbMaster = Workbooks.Add
        m = wbMaster.Sheets.Count
        n = m
        For Each f In dict(k) ' files in collection
            Set wb = Workbooks.Open(FOLDER & f, 1, 1)
            s = Replace(Mid(f, Len(k) + 1), ".xlsx", "")
            ' remove _ from front
            If SEP_COUNT > 0 And Left(s, 1) = "_" Then s = Mid(s, 2)
            For Each ws In wb.Sheets
                ws.Copy After:=wbMaster.Sheets(n)
                n = n + 1
                wbMaster.Sheets(n).Name = s & "_" & ws.Name
            Next
            wb.Close False
        Next

        ' delete initial sheets
        Application.DisplayAlerts = False
        For n = m To 1 Step -1
            wbMaster.Sheets(n).Delete
        Next
        Application.DisplayAlerts = True
     
        ' save master
        wbMaster.SaveAs FOLDER & "Master_" & k & ".xlsx", _
               FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
        wbMaster.Close False
    Next
    ' end
    Application.ScreenUpdating = True
    MsgBox dict.Count & " master files created", vbInformation

End Sub

Convert your current sub to accept the letter pattern and call it by a main one feeding all wanted letters将您当前的子转换为接受字母模式,并由一个主要的调用它来提供所有想要的字母

Sub Merge()
    Const letters As String = "ABCDEFG" ' collect all wanted initial letters
    
    Dim iLetter As Long
        For iLetter = 1 To Len(letters) ' loop through letters
            MergeLetter String(4,Mid$(letters, iLetter, 1))
        Next
    
End Sub

and here's your original Merge() sub, I adapted for the task:这是你原来的Merge()子,我适应了这个任务:

Sub MergeLetter(letter As String)

    Dim masterWb As Workbook  
        Set masterWb = Workbooks.Add 'open a new "master" workbook

    Dim path As String
        path = "C:\Temp\"
    
        Dim fileName As String
            fileName = Dir(path & letter & "*.xlsx")
        
            Do While fileName <> vbNullString

                With Workbooks.Open(fileName:=path & fileName, ReadOnly:=True)
                    Dim sh As Worksheet
                        For Each sh In .Worksheets
                           sh.Copy After:=masterWb.Sheets(1)
                        Next
                        .Close
                End With

                fileName = Dir()

            Loop
     
            With masterWb
                .SaveAs fileName:=path & letter & ".xlsx", FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
                .Close False
            End With
End Sub

as you see, I also adopted some stylistic changes, one of them being my personal code indentation pattern, which you may found userful or not如您所见,我还采用了一些样式更改,其中之一是我的个人代码缩进模式,您可能会发现它有用或无用

Merge Sheets from Multiple Workbooks to Master Workbooks将多个工作簿中的工作表合并到主工作簿

  • The code should be located in a module of a file that is not inside the source folder path ( FolderPath ) or at least a file whose name has none of the prefixes.代码应位于不在源文件夹路径 ( FolderPath ) 内的文件的模块中,或者至少位于名称没有任何前缀的文件中。
  • Not tested.未测试。
Option Explicit

Sub mergeSheets()
    
    Const FolderPath As String = "C:\Temp\"
    Const PrefixesList As String = "AAAA,BBBB,CCCC"
    
    Dim Prefixes() As String: Prefixes = Split(PrefixesList, ",")
    
    Dim swb As Workbook
    Dim dwb As Workbook
    Dim sh As Object
    Dim fName As String
    Dim n As Long
    Dim dshCount As Long
        
    Application.ScreenUpdating = False
        
    For n = 0 To UBound(Prefixes)
        fName = Dir(FolderPath & Prefixes(n) & "*.xlsx")
        dshCount = 0
        Do Until Len(fName) = 0
            Set swb = Workbooks.Open(FolderPath & fName, , True)
            For Each sh In swb.Sheets ' charts and what not included
                If dshCount = 0 Then
                    sh.Copy ' creates a new workbook containing one sheet
                    Set dwb = ActiveWorkbook
                Else
                    sh.Copy After:=dwb.Sheets(dshCount)
                End If
                dshCount = dshCount + 1
            Next sh
            swb.Close SaveChanges:=False
            fName = Dir
        Loop
        ' Maybe you wanna rather do '... & Prefixes(n) & ".xlsx",...'
        dwb.SaveAs "C:\Temp\File_" & dwb.WorkSheets(1).Range("A1") & ".xlsx", _
            xlOpenXMLWorkbook, , , , False
        dwb.Close
    Next n

    Application.ScreenUpdating = True

End Sub

Create a class Named WorkbookMerger and add the following code into it创建一个名为WorkbookMergerclass并将以下代码添加到其中

Option Explicit
''Add/check Tools> Reference> Microsoft Scripting Runtime

Private FileSysObject As Scripting.FileSystemObject
Private Fullfolder  As Scripting.Folder
Private SingleFile As Scripting.File
Private dict As Scripting.Dictionary
Private ProccessedFolder As String

Private Const Delim As String = "_"
Private Const SaveInFolder As String = "ProccessedFiles"

Public Function Execute(ByVal BasePath As String) As Boolean
    Set Fullfolder = FileSysObject.GetFolder(BasePath)
     
    ProccessedFolder = FileSysObject.BuildPath(BasePath, SaveInFolder)
    
    Execute = False
    If Not FileSysObject.FolderExists(ProccessedFolder) Then
        FileSysObject.CreateFolder (ProccessedFolder)
    End If
    
    If ReadPatterns Is Nothing Then
        Exit Function
    Else
        ProcessFiles
    End If
    Execute = True
End Function

Private Function ReadPatterns() As Scripting.Dictionary
    For Each SingleFile In Fullfolder.Files
    
        Dim Pattern As String
        Pattern = Split(SingleFile.Name, Delim)(0) 'change delimeter
        
        On Error Resume Next
        If Not dict.Exists(Pattern) Then dict.Add Pattern, CStr(Pattern)

    Next SingleFile
    Set ReadPatterns = dict
End Function

Private Sub ProcessFiles()

    Dim key As Variant
    For Each key In dict
        'loop through all patterns in dict and process each file if it matches

        Dim masterWb As Workbook
        Dim masterwbName As String
        masterwbName = ProccessedFolder & "\" & key & ".xlsx"
        If FileSysObject.FileExists(masterwbName) Then
            Set masterWb = Workbooks.Open(masterwbName)
        Else
            Set masterWb = Workbooks.Add
        End If

        For Each SingleFile In Fullfolder.Files
            With SingleFile
        
                If .Name Like key & "*" Then
            
                    Dim Wsheet As Worksheet
                    Dim wb As Workbook
                    Set wb = Workbooks.Open(Fullfolder.Path & "\" & SingleFile.Name, ReadOnly:=True)
                    For Each Wsheet In wb.Worksheets
                        Wsheet.Copy after:=masterWb.Sheets(1)
                    
                    Next Wsheet
                    wb.Close False
                    'close file without saving any changes
                End If
            End With
                    
        Next SingleFile
        With masterWb
            .SaveAs masterwbName, xlOpenXMLWorkbook
            .Close True
        End With

    Next key
End Sub

Private Sub Class_Initialize()
    Set FileSysObject = New Scripting.FileSystemObject
    Set dict = New Scripting.Dictionary
End Sub

Now in any module add the following code现在在任何module中添加以下代码

Public Sub Testing()
    Dim WMerger As WorkbookMerger
    Set WMerger = New WorkbookMerger
    On Error GoTo ErrorExit:
    With Application
        '.Calculation = xlCalculationAutomatic
        .Calculation = xlCalculationManual
        .ScreenUpdating = False
        .EnableCancelKey = xlInterrupt
    End With
    
    If WMerger.Execute("C:\Temp") Then MsgBox "Completed"

ErrorExit:
    
    With Application
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
        .StatusBar = False
    End With
End Sub
  1. The class takes basepath and based on constant SaveInFolder it creates a sub-folder under basepath where all processed files will be stored. class 采用基本路径,并基于常量SaveInFolder在基本路径下创建一个子文件夹,所有处理过的文件都将存储在其中。
  2. Reads all file in basepath and retrieves unique patterns based on the Delim .读取基本路径中的所有文件并根据Delim检索唯一模式。
  3. Loop through each key(unique pattern), Create file base don pattern and process all filenames again to check if any of the file name matches this pattern.循环遍历每个键(唯一模式),创建文件基础 don 模式并再次处理所有文件名以检查是否有任何文件名与此模式匹配。
  4. If matches it's worksheets will be copied in this new file and at last this file will be saved in sub folder with Pattern name.如果匹配,它的工作表将被复制到这个新文件中,最后这个文件将保存在带有模式名称的子文件夹中。

I tried with 20 different files with different patterns and it works as expected.我尝试了 20 个具有不同模式的不同文件,它按预期工作。 Let me now if it works.现在让我看看它是否有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM