【问题标题】:Copying duplicating issue复制复制问题
【发布时间】:2022-01-25 21:08:56
【问题描述】:

我编写了下一个代码,将某个工作表从我的活动工作簿复制到多个工作簿,但它不断复制副本,这是我的第一个问题, 下一个我希望该代码影响其中的文件夹和子文件夹如何做到这一点。 代码是:

Option Explicit
Public Sub CopySheetToAllWorkbooksInFolder()
    Dim sourceWorkbook As Workbook
    Dim sourceSheet As Worksheet
    Dim destinationWorkbook As Workbook
    Dim folder As String, filename As String
    'Worksheet in active workbook to be copied as a new sheet to the destination workbook
    Set sourceWorkbook = ActiveWorkbook
    Set sourceSheet = sourceWorkbook.Worksheets("pay")
    'Folder containing the destination workbooks
    folder = "J:\2021\hager\test\"
    filename = Dir(folder & "*.xlsx", vbNormal)
    While Len(filename) <> 0
        Debug.Print folder & filename
        Set destinationWorkbook = Workbooks.Open(folder & filename)
        sourceSheet.Copy after:=destinationWorkbook.Sheets(1)
        destinationWorkbook.ChangeLink Name:=sourceWorkbook.Name, NewName:=destinationWorkbook.Name
        destinationWorkbook.Close True
        filename = Dir()  ' Get next matching file
    Wend
End Sub

因为付款是工作表,文件夹是我的目标文件夹。

【问题讨论】:

  • 请更好地阐明“它不断复制副本”的含义。然后,您的活动代码将更新已定义文件夹中的工作簿,但不会更新其子文件夹中的工作簿。
  • 我的意思是它不断复制我想复制的工作表,比如在目标工作簿 pay1、pay2、pay3 等中复制很多;我问有没有办法让它影响工作簿在子文件夹中也是如此。
  • 我可以向您展示如何从文件夹和子文件夹中更新所有工作簿(一种非常快速的方法),但看起来您的安装有问题。如果您使用 sourceSheet.Copy 之后没有任何参数,Excel 将创建一个仅包含复制工作表的新工作簿。但是如果你使用sourceSheet.Copy after:=destinationWorkbook.Sheets(1),它不应该以这种方式表现......让我指出方法描述。请看here。您使用什么 Excel/Office 版本?
  • office 2016 和上面的代码一样,我已经在使用 sourceSheet.Copy after:=destinationWorkbook.Sheets(1) 但我不知道为什么它会不断重复工作表,有时它可能超过 10 张相同的工作簿
  • 请更好地澄清这个问题...是否有超过 10 个仅包含复制工作表的工作簿,或仅包含复制工作表?如果是最后一个变体,那些工作表在哪里?

标签: excel vba


【解决方案1】:

将工作表添加到多个文件

  • 这会将活动工作簿的工作表复制到文件夹及其所有子文件夹 (/s) 中的所有相关 (.xlsx) 文件中。
  • 它将跳过已经包含工作表的文件。
  • 如果代码在包含工作表 (Pay) 的工作簿中,请将 ActiveWorkbook 替换为 ThisWorkbook
Option Explicit

Sub CopySheetToAllWorkbooksInFolder()
    Const ProcName As String = "CopySheetToAllWorkbooksInFolder"
    On Error GoTo ClearError
    
    Const dFolderPath As String = "J:\2021\hager\test\"
    Const dFilePattern As String = "*.xlsx"
    Const swsName As String = "Pay"
    
    Dim fCount As Long
    
    Dim dFilePaths() As String
    dFilePaths = ArrFilePaths(dFolderPath, dFilePattern)
    If UBound(dFilePaths) = -1 Then Exit Sub ' no files found
    
    Dim swb As Workbook: Set swb = ActiveWorkbook ' ThisWorkbook ' 
    Dim sws As Worksheet: Set sws = swb.Worksheets(swsName)
    
    Dim dwb As Workbook
    Dim n As Long
    
    For n = 0 To UBound(dFilePaths)
        Debug.Print "Opening... " & dFilePaths(n)
        Set dwb = Workbooks.Open(dFilePaths(n))
        If Not SheetExists(dwb, swsName) Then
            sws.Copy After:=dwb.Sheets(1)
            'dwb.ChangeLink swb.Name, dwb.Name ' doesn't work for me
            fCount = fCount + 1
            Debug.Print "Worksheet added to... " & fCount & ". " & dFilePaths(n)
        End If
        dwb.Close SaveChanges:=True
    Next n
    
    MsgBox "Worksheet inserted in " & fCount & " workbook(s).", vbInformation

ProcExit:
    Exit Sub
ClearError:
    Debug.Print "'" & ProcName & "' Rte '" & Err.Number & "':" & vbLf _
        & "    " & Err.Description
    Resume ProcExit
End Sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose:      Returns the file paths of the files of a folder in an array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function ArrFilePaths( _
    ByVal FolderPath As String, _
    Optional ByVal FilePattern As String = "*.*", _
    Optional ByVal DirSwitches As String = "/s/b/a-d") _
As Variant
    Const ProcName As String = "ArrFilePaths"
    On Error GoTo ClearError
    
    Dim pSep As String: pSep = Application.PathSeparator
    If Right(FolderPath, 1) <> pSep Then FolderPath = FolderPath & pSep
    Dim ExecString As String ' '%comspec%' or 'cmd.exe' ?
    ExecString = "%comspec% /c Dir """ _
        & FolderPath & FilePattern & """ " & DirSwitches
    Dim Arr() As String: Arr = Split(CreateObject("WScript.Shell") _
        .Exec(ExecString).StdOut.ReadAll, vbCrLf)
    If UBound(arr) > 0 Then
        ReDim Preserve arr(0 To UBound(arr) - 1)
    End If
    ArrFilePaths = arr

ProcExit:
    Exit Function
ClearError:
    Debug.Print "'" & ProcName & "' Rte '" & Err.Number & "':" & vbLf _
        & "    " & Err.Description
    Resume ProcExit
End Function

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose:      Returns a boolean indicating wether a sheet, defined
'               by its name ('SheetName'), exists in a workbook ('wb').
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function SheetExists( _
    ByVal wb As Workbook, _
    ByVal SheetName As String) _
As Boolean
    On Error GoTo ClearError

    Dim Sh As Object: Set Sh = wb.Sheets(SheetName)
    SheetExists = True
    
ProcExit:
    Exit Function
ClearError:
    Resume ProcExit
End Function

【讨论】:

  • 没有任何效果抱歉。
  • 这是什么意思?你收到消息了吗? Immediate window Ctrl+G 中写的是什么?另外,在我的帖子开头,它说什么时候可以工作。
  • 我按照你说的做了,但它说找不到路径。
  • 我已经修改了我的答案几次。尝试再次复制代码。
  • 仍然给我同样的错误;它会这样做,因为我改变了语言???
【解决方案2】:

这将遍历文件夹和子文件夹中的工作簿。如果 pay 表不存在,它只会复制它。

Option Explicit

Public Sub CopySheetToAllWorkbooksInFolder()

    Const WS_NAME = "pay"
    Const folder = "J:\2021\hager\test\" ' destination workbooks

    Dim wbSrc As Workbook, wbDest As Workbook
    Dim wsSrc As Worksheet, wsDest As Worksheet
    Dim FSO As Object, ts As Object
    Dim flds As Collection, fld As Object, f As Object
    Dim i As Long, n As Long, bExists As Boolean, logfile As String
    
    ' logfile
    logfile = Format(Now, "yyyyddmm_HHMMSS") & "_log.txt"
    Set FSO = CreateObject("Scripting.FileSystemObject")
    Set ts = FSO.createTextFile(logfile)
    
    Set wbSrc = ActiveWorkbook
    Set wsSrc = wbSrc.Sheets(WS_NAME)
    Set flds = New Collection
    
    If FSO.FolderExists(folder) Then
    
      ' collection of folders and subfolders
       Call GetFolders(FSO, folder, flds)
       
       'scan folders
       Application.ScreenUpdating = False
       For i = 1 To flds.Count
            ts.writeLine "---- Folder = " & flds(i)
            ' scan folder for files
            For Each f In flds(i).Files
               
                If f.Name Like "*.xlsx" Then
                    Set wbDest = Workbooks.Open(f.Path)
                    
                    ' check if sheet already exists
                    bExists = False
                    For Each wsDest In wbDest.Sheets
                        If wsDest.Name = WS_NAME Then
                            bExists = True
                            Exit For
                        End If
                    Next
             
                    ' copy sheet if not exists
                    If bExists = False Then
                        wsSrc.Copy after:=wbDest.Sheets(1)
                        wbDest.ChangeLink Name:=wbSrc.Name, NewName:=wbDest.Name
                        wbDest.Close savechanges:=True
                        n = n + 1
                        ts.writeLine f.Path & " inserted " & WS_NAME
                    Else
                        wbDest.Close savechanges:=False
                        ts.writeLine f.Path & " existing sheet " & WS_NAME
                    End If
                Else
                    ts.writeLine f.Path & " Skipped"
                End If
            Next
        Next
        MsgBox n & " sheets inserted see " & logfile, vbInformation
    Else
        MsgBox "Folder : " & folder, vbCritical, "Folder not found"
    End If
    ts.Close
    Application.ScreenUpdating = True   
End Sub

Sub GetFolders(FSO, s As String, ByRef flds)
    Dim fld As Object
    Set fld = FSO.getfolder(s)
    flds.Add fld
    For Each fld In fld.subfolders
        Call GetFolders(FSO, fld.Path, flds) ' recurse
    Next
End Sub

【讨论】:

  • 这个和我兄弟一起工作了很多,但它可以在所有子级别上。
  • @mohamed ok 查看更新的代码和新的子例程 GetFolders。
【解决方案3】:

请使用下一个函数,它将返回一个包含所有符合“.xls*”扩展名条件的文件的数组:

Private Function allFiles(strFold As String, Optional ext As String = "") As Variant 'super, super fast...
  Dim arr
  arr = Filter(Split(CreateObject("wscript.shell").exec("cmd /c dir """ & strFold & """ /b /s").StdOut.ReadAll, vbCrLf), "\")
  If ext <> "" Then
    Dim arrFin, arrExt, El, i As Long
    ReDim arrFin(UBound(arr))
      For Each El In arr
         arrExt = Split(El, ".")
         If arrExt(UBound(arrExt)) Like ext Then
             arrFin(i) = El: i = i + 1
         End If
      Next El
      ReDim Preserve arrFin(i - 1)
      allFiles = arrFin
  Else
      allFiles = arr
  End If
End Function

然后在你的代码中用下一种方式:

Public Sub CopySheetToAllWorkbooksInFolder()
    Dim sourceWorkbook As Workbook, sourceSheet As Worksheet, destinationWorkbook As Workbook
    Dim folder As String, arr, El
    
    'Worksheet in active workbook to be copied as a new sheet to the destination workbook
    Set sourceWorkbook = ActiveWorkbook
    Set sourceSheet = sourceWorkbook.Worksheets("pay")
    'Folder containing the destination workbooks
    folder = "J:\2021\hager\test\"
    arr = allFiles(folder, "xls*")
    For Each El In arr
        Debug.Print El: Stop 'run the code line by line pressing F8
        Set destinationWorkbook = Workbooks.Open(El)
        sourceSheet.copy After:=destinationWorkbook.Sheets(1)
        destinationWorkbook.ChangeLink Name:=sourceWorkbook.Name, newName:=destinationWorkbook.Name
        destinationWorkbook.Close True
    Next El
End Sub

当上面的代码将停止在Debug.Print El 行时,逐行运行它,按下F8 看看会发生什么。如果 ie 按您的需要工作,请在讨论中评论代码行并按F5 运行所有代码。

请在测试后发送一些反馈。

【讨论】:

  • 抱歉,我无法运行私有函数。
  • @Mohamed Nabil 从哪里尝试运行它?我的意思是在哪个代码模块中?然后将其设为 Public... 但它应该存在于 标准模块 中!并且Sub 调用它也应该在那里......你明白这是什么意思吗?
  • 我将它添加到模块中并尝试从公式选项卡运行它
  • @Mohamed 从公式标签运行什么?您是否尝试将该功能用作 UDF 功能?你怎么称呼你以前的Sub?请在这里写下您使用的是什么。您应该使用相同的调用! Sub 正在调用函数...
  • @Mohamed 从公式标签运行什么?您是否尝试将该功能用作 UDF 功能?你怎么称呼你以前的Sub?请在这里写下您使用的内容。您应该使用相同的调用! Sub 正在调用该函数...请尝试在一张纸上添加一个按钮/形状,将子 CopySheetToAllWorkbooksInFolder 分配给它并按下它。为了分配Sub,请尝试右键单击-> 分配宏...(设置“宏在:此工作簿”)并选择相应的...
猜你喜欢
  • 2018-05-22
  • 2015-10-18
  • 2021-08-01
  • 2012-01-09
  • 2019-01-14
  • 1970-01-01
  • 1970-01-01
  • 2019-07-04
相关资源
最近更新 更多