excel 中多个文件和路径的复制、重命名和验证成功

Copy, rename and validate success of multiple files and paths in excel

Solution Template SetUp

在过去的 5 天里,我一直在这里和网上四处搜寻,以找到适用于多个文件的东西。上午的许多 night/early 小时未能成功拼凑 together/coding 得到结果。提前致谢。

以下代码来自get-digital-help.com/copyrename-a-file-excel-vba作者Oscar 它适用于 1 个文件,我有 8,000 个文件要在深层文件夹结构中执行,所以但我真的希望每一行都查看源路径、源文件名、目标路径和目标文件:

每一行:

E 列写“成功”或“失败”验证。

不错have/completely可选!!! :)

  1. 检查源文件 A 列和 B 列是否存在,= F 列中的 True 或 False。如果为 True,则继续复制并重命名。
  2. 如果目标文件已经存在,则失败并且列 F = 重复
  3. 保留第一行以放入第 header 列名称。
<pre><code>Sub CopyRenameFile() 'Dimension variables and declare data types Dim src As String, dst As String, fl As String Dim rfl As String 'Save source directory specified in cell A2 to variable src src = Range("A2") 'Save destination directory specified in cell C2 to variable dst dst = Range("C2") 'Save file name specified in cell B2 to variable fl fl = Range("B2") 'Save new file name specified in cell D2 to variable rfl rfl = Range("D2") 'Enable error handling On Error Resume Next 'Copy file based on variables src and fl to destination folder based on variable dst and name file based on value in rfl FileCopy src & "\" & fl, dst & "\" & rfl 'Check if an error has occurred If Err.Number <> 0 Then 'Show error using message box MsgBox "Copy error: " & src & "\" & rfl End If 'Disable error handling On Error GoTo 0 End Sub

使用文件列表复制文件

  • 这个解决方案由三个过程组成。你运行只有第一个:copyRenameFile。另外两个 getOffsetColumnwriteOffsetRange 在必要时由第一个调用。

  • 最好用新的工作簿进行测试。插入一个模块并将代码复制到其中。现在打开您的原始工作簿并将某些值复制到例如Sheet1 的新工作簿。由于代码是为 Thisworkbook(包含此代码的工作簿)编写的,因此原始工作簿将是安全的(不会写入)。

  • 首先调整常量部分中的值(标题为 WorksheetOther)。然后测试空工作表。然后用 A 列中的一个文件夹进行测试,然后用 more 慢慢地继续测试其他列。可能的错误应该被抑制,它们的消息(描述)应该出现在 VBEImmediate window (CTRL+G ).

  • 作为本次调查的副产品,我还添加了 createFolders 功能以在 MkDir 'cannot' 的一种情况下创建文件夹,以及两个过程测试一下。

代码

Option Explicit

Sub copyRenameFile()

    ' Initialize error handling.
    Const ProcName As String = "copyRenameFile"
    On Error GoTo clearError ' Turn on error trapping.
    
    ' Worksheet
    Const wsName As String = "Sheet1"        ' Worksheet Name
    Const FirstRow As Long = 2               ' First Row Number
    Const LastRowCol As Variant = "A"        ' Last Row Column Index
    Dim srcCols As Variant                   ' Source Columns Array
    srcCols = VBA.Array("A", "B", "C", "D")
    Dim tgtCols As Variant                   ' Target Columns Array
    tgtCols = VBA.Array("E", "F")
    
    ' Other
    Dim filMsg() As Variant                  ' File Messages
    filMsg = VBA.Array("Fail", "Success")
    Dim folMsg() As Variant                  ' Folder Messages
    folMsg = VBA.Array(False, True, "Duplicate")
    Dim PathDelimiter As String
    PathDelimiter = Application.PathSeparator
    Dim wb As Workbook
    Set wb = ThisWorkbook ' 'Thisworkbook' is the workbook containing this code.
    
    ' Define Last Row Column Range ('rng').
    Dim ws As Worksheet
    Set ws = wb.Worksheets(wsName)
    Dim LastRow As Long
    LastRow = ws.Cells(ws.Rows.Count, LastRowCol).End(xlUp).Row
    If LastRow < FirstRow Then
        GoTo FirstRowBelowLastRow
    End If
    Dim rng As Range
    Set rng = ws.Range(ws.Cells(FirstRow, LastRowCol), _
                       ws.Cells(LastRow, LastRowCol))
     
    ' Write Source Column Ranges to Source Jagged Array ('Source').
    Dim ubcS As Long
    ubcS = UBound(srcCols)
    Dim Source As Variant
    ReDim Source(0 To ubcS)
    Dim Data As Variant
    Dim j As Long
    For j = 0 To ubcS
        getOffsetColumn Data, srcCols(j), rng
        Source(j) = Data
    Next j
    
    ' Define Target Jagged Array ('Target').
    Dim ubcT As Long
    ubcT = UBound(tgtCols)
    Dim ubs As Long
    ubs = UBound(Source(0))
    Dim Target As Variant
    ReDim Target(0 To ubcT)
    ReDim Data(1 To ubs, 1 To 1)
    For j = 0 To ubcT
        Target(j) = Data
    Next j
    
    ' Declare additional variables for the For Next loop.
    Dim i As Long
    Dim Copied As Long
    Dim srcPath As String
    Dim tgtPath As String
    
    ' Loop through rows of arrays of Source Jagged Array, check folders,
    ' check files and finally copy if condition is met. At the same time
    ' write results to arrays of Target Jagged Array.
    ' The condition to copy is met when source file exists,
    ' and target file does not.
    
    For i = 1 To ubs
        
        ' Folders
        srcPath = Source(0)(i, 1)
        If Dir(srcPath, vbDirectory) = "" Then
            ' Source Folder and Source File do not exist.
            Target(0)(i, 1) = filMsg(0)
            Target(1)(i, 1) = folMsg(0)
            GoTo NextRow
        End If
        ' Source Folder exists.
        tgtPath = Source(1)(i, 1)
        If Dir(tgtPath, vbDirectory) = "" Then
            ' Target Folder and Target File do not exist.
            Target(0)(i, 1) = filMsg(0)
            Target(1)(i, 1) = folMsg(0)
            GoTo NextRow
        End If
        ' Source Folder and Target Folder exist.
        
        ' Files
        srcPath = srcPath & PathDelimiter & Source(2)(i, 1)
        If Dir(srcPath) = "" Then
            ' Source File does not exist.
            Target(0)(i, 1) = filMsg(0)
            Target(1)(i, 1) = folMsg(0)
            GoTo NextRow
        End If
        ' Source File exists.
        tgtPath = tgtPath & PathDelimiter & Source(3)(i, 1)
        If Dir(tgtPath) <> "" Then
            ' Target File exists.
            Target(0)(i, 1) = filMsg(0)
            Target(1)(i, 1) = folMsg(2)
            GoTo NextRow
        End If
        ' Source File exists and Target File does not.
        Target(0)(i, 1) = filMsg(1)
        Target(1)(i, 1) = folMsg(1)
        
        ' Copy
        FileCopy srcPath, tgtPath
        ' Count files copied.
        Copied = Copied + 1
         
NextRow:
    Next i
    
    ' Write values (results) from arrays of Target Jagged Array
    ' to Target Columns.
    For j = 0 To ubcT
        writeOffsetRange Target(j), tgtCols(j), rng
    Next j

    ' Inform user.
    MsgBox "Copied " & Copied & " files.", vbInformation, "Success"

ProcExit:
    Exit Sub

FirstRowBelowLastRow:
    Debug.Print "'" & ProcName & "': First row below last row."
    GoTo ProcExit

clearError:
    Debug.Print "'" & ProcName & "': " & vbLf _
              & "    " & "Run-time error '" & Err.Number & "':" & vbLf _
              & "        " & Err.Description
    On Error GoTo 0 ' Turn off error trapping.
    GoTo ProcExit
    
End Sub

Sub getOffsetColumn(ByRef Data As Variant, _
                    OffsetColumnIndex As Variant, _
                    ColumnRange As Range)
    
    ' Initialize error handling.
    Const ProcName As String = "getOffsetColumn"
    On Error GoTo clearError ' Turn on error trapping.
    
    Data = Empty
    If ColumnRange Is Nothing Then
        GoTo NoRange
    End If
    
    Dim ws As Worksheet
    Set ws = ColumnRange.Worksheet
    
    If ColumnRange.Rows.Count > 1 Then
        Data = ColumnRange.Offset(, ws.Columns(OffsetColumnIndex).Column _
                                  - ColumnRange.Column) _
                          .Value
    Else
        ReDim Data(1 To 1, 1 To 1)
        Data(1, 1) = ColumnRange.Offset(, ws.Columns(OffsetColumnIndex) _
                                            .Column _
                                        - ColumnRange.Column) _
                                .Value
    End If

ProcExit:
    Exit Sub

NoRange:
    Debug.Print "'" & ProcName & "': No Range."
    GoTo ProcExit

clearError:
    Debug.Print "'" & ProcName & "': " & vbLf _
              & "    " & "Run-time error '" & Err.Number & "':" & vbLf _
              & "        " & Err.Description
    On Error GoTo 0 ' Turn off error trapping.
    GoTo ProcExit

End Sub

Sub writeOffsetRange(Data As Variant, _
                     OffsetColumnIndex As Variant, _
                     ColumnRange As Range)
    
    ' Initialize error handling.
    Const ProcName As String = "writeOffsetColumn"
    On Error GoTo clearError ' Turn on error trapping.
    
    If ColumnRange Is Nothing Then
        GoTo NoRange
    End If
    
    Dim ws As Worksheet
    Set ws = ColumnRange.Worksheet
    
    ColumnRange.Offset(, ws.Columns(OffsetColumnIndex).Column _
                       - ColumnRange.Column).Value = Data

ProcExit:
    Exit Sub

NoRange:
    Debug.Print "'" & ProcName & "': No Range."
    GoTo ProcExit

clearError:
    Debug.Print "'" & ProcName & "': " & vbLf _
              & "    " & "Run-time error '" & Err.Number & "':" & vbLf _
              & "        " & Err.Description
    On Error GoTo 0 ' Turn off error trapping.
    GoTo ProcExit

End Sub

副产品

' e.g. "C:\Test" is an existing folder, "C:\Test\Test1" is not.
' When you want to create the folder "C:\Test\Test1\Test2", 'MkDir' will return
' "Run-time error '76': Path Not found", because "C:\Test\Test1" does not exist.
' The 'createFolders' function remedies this by creating as many folders
' as needed. In the previous example it first creates "C:\Test\Test1" and
' only then creates "C:\Test\Test1\Test2" in it.
' The function returns 'True' if the folder previously existed or now exists.
' The function returns 'False' if 'PathString' is invalid.
Function createFolders(PathString As String) As Boolean
    
    ' Initialize error handling.
    Const ProcName As String = "createFolders"
    On Error GoTo clearError ' Turn on error trapping.

    ' Split Path String ('PathString') by System Path Separator ('Delimiter')
    ' into 1D zero-based Folders Array 'Folders()'.
    Dim Delimiter As String
    Delimiter = Application.PathSeparator
    Dim Folders() As String
    Folders = Split(PathString, Delimiter)
    
    ' Define Last Subscript ('LastSS') to be considered, because Path String
    ' could be ending with a System Path Separator.
    Dim LastSS As Long
    LastSS = UBound(Folders)
    If Folders(LastSS) = "" Then
        LastSS = LastSS - 1
    End If
    
    ' Using Folders Array, write paths to Paths Array ('Paths()').
    Dim Paths() As String
    ReDim Paths(0 To LastSS)
    Paths(0) = Folders(0)
    Dim j As Long
    If LastSS > 0 Then
        For j = 1 To LastSS
            Paths(j) = Paths(j - 1) & Delimiter & Folders(j)
        Next j
    End If
    
    ' Create each folder if it does not exist.
    For j = 0 To LastSS
        If Dir(Paths(j), vbDirectory) = "" Then
            MkDir Paths(j)
        End If
    Next j
    
    ' Write result.
    createFolders = True
    
ProcExit:
    Exit Function

clearError:
    Debug.Print "'" & ProcName & "': " & vbLf _
              & "    " & "Run-time error '" & Err.Number & "':" & vbLf _
              & "        " & Err.Description
    On Error GoTo 0 ' Turn off error trapping.
    GoTo ProcExit
    
End Function

Sub testCreateFolders()
    Const PathString As String = "C:\Test\Test1\Test2"
    Dim Result As Boolean
    Result = createFolders(PathString)
    If Result Then
        MsgBox "If the path previously didn't exist, now it certainly does."
    Else
        MsgBox "The supplied path is invalid."
    End If
End Sub

Sub testMkDir()
    Const PathString As String = "C:\Test\Test1\Test2"
    MkDir PathString
End Sub