Moving files to a subfolder based on partial filename with VBA

Booker

New Member
Joined
Jan 9, 2020
Messages
3
Office Version
  1. 365
Platform
  1. Windows
Hi, at work I am constantly moving email files (.msg) to certain subfolders based on the number of the file and it takes up a lot of my time so I've been trying to automatize with VBA recently. However, I could only manage (I am a beginner at VBA btw) to create a script to move the files to a folder if the name of the file coincides with the name of the folder. The problem is that the name of the file matches the name of the subfolder only partially. We create a folder for each deal we have and those deals are each identified by a 6 digit number. Then we name all the files pertaining to that specific deal with a numerical sequence.

For example, let's say we have a deal #567567. We create a subfolder called 567567. Then we numerate all files related to that deal as this: 01 - 567567, 02 - 567567, 03 - 567567 and so on. I then move those files to the corresponding folder manually. I was wondering if there was any way to automatize this with VBA considering only a part of the file name matches with the destination folder name. Thank you!
 

Excel Facts

Links? Where??
If Excel says you have links but you can't find them, go to Formulas, Name Manager. Look for old links to dead workbooks & delete.
Hi Booker,

There are several issues you need to address.
  1. Extract the correct subdirectory name or #deal from the file name
  2. Identify if the correct directory / file relationship (assuming your 01 - 567567, 02 - 567567 format always holds true)
  3. Confirm if the sub directory exists (if it doesn't then what happens?)
  4. If the directory exists AND the file is correctly identified, then move the file as required
Point 1
The following code accepts a file name as a string and returns the subdirectory name (based on your original post)
VBA Code:
Public Function Return_SubDirectory_Name(FileName As String) As String
    
    'define a string array
    Dim Splitter() As String
    
    ' check if we have a filename with a length > 0  - i.e. no empty filenames
    If Len(FileName) > 0 Then
        ' let's assume the filename is "02 - 123456.pdf"
        ' Split creates a string array with the " - " as the break point - notice the space before and after the "-" character
        ' element 0 in the array will hold "02"
        ' element 1 in the array will hold "12345.pdf
        Splitter = Split(FileName, " - ")
        
        ' test to make sure the array has JUST two elements
        ' 1st element of ANY array starts with zero
        ' logic would need to be adjusted if file name was something like "02 - 12345 - 123.pdf" - as plsit function would create more elements
        If UBound(Splitter) = 1 Then
            
            ' now splitter (1) holes the value "123456.pdf"
            ' split out the ".pdf" or whatever file extention
            
            Splitter = Split(Splitter(1), ".")
            ' element (0) now just holds "123456" - this *SHOULD* be the sub directory or deal #
            
            Return_SubDirectory_Name = CStr(Splitter(0))
            
            ' now exit the function
            Exit Function
        End If
        
        ' if above logic didn't work (maybe weird file name or whatever) - then drop out here with vbnullstring (empty) filename
        Return_SubDirectory_Name = vbNullString
    
    End If
    
End Function


Points 2 / 4
The following code accepts a search path (something like "C:\Desktop\MyFiles").
It also uses a nominated archive path where you want the files saved AND the type of files (.msg or whatever) you're looking for.
It then makes a copy of the required file, saves it to the target archive file and finally deletes the original file

VBA Code:
Public Sub Check_Files(Search_Path As String)

    Dim File_Name As String
    Dim File_Type As String
    
    Dim strFileName As String
    Dim Deal_Name As String
    
    Dim Archive_Path As String
    Dim Target_Path As String
    
    Dim File_Count As Integer
    
    ' setup where the archive directory is - maybe a network location?
    ' I'll assume it is the same directory path as the work book - change the following path as required
    ' path should be in a format like "C:\Desktop\MyFiles" or something
    Archive_Path = ThisWorkbook.Path
    
    ' the search_path is handed into the function as an arguement
    ' checks the Search path - this path is where the file currently are - maybe different than where you want to archive them
    Confirm_Directory Search_Path
    
    ' changes excel's default directory path to the one you want to search
    ChDir Search_Path

    ' assumes .msg files, but could be .pdf files - make changes as needed
    File_Type = Search_Path & "*.msg"

    ' identifies file name within the target directory
    strFileName = Dir(File_Type)
    
    ' cycles through each file within the search directory - will continue until the length of the strFileName = 0 (i.e. no files)
    Do While Len(strFileName) > 0
        
        ' get the sub directory or #deal name
        Deal_Name = Return_SubDirectory_Name(strFileName)
        
        ' test if we have a valid deal name (not a vbnullstring)
        If Len(Deal_Name) > 0 Then
        
            ' update the target_path - the target path will change as the different #deal name subdirectories within the archive path change
            Target_Path = Archive_Path & "\" & Deal_Name
        
            ' checks if THAT target archive path exists - makes one if it doesn't
            Confirm_Directory Target_Path
            
            ' copy required file to the target archive directory
            FileCopy Search_Path & "\" & strFileName, Target_Path & "\" & strFileName

            ' delete original copy from search directory
            Kill Search_Path & "\" & strFileName
        
            File_Count = File_Count + 1
        
        End If
        
        ' aquires the next filename in the search directory
        strFileName = Dir
        
    Loop

    Debug.Print "Moved " & File_Count & " file(s)"

End Sub

Point 3
The following code will confirm if a directory exists and if it doesn't, it will create the required sub directory

VBA Code:
Public Sub Confirm_Directory(This_Path As String)
    ' used to test for directory locations
    ' will make sub directories if required
    
    Dim Splitter() As String
    Dim Test_Path As String
    
    If Dir(This_Path, vbDirectory) <> vbNullString Then
    
        Splitter = Split(This_Path, "\")
        
        For I = LBound(Splitter) To UBound(Splitter)
            If I = 0 Then
                Test_Path = Splitter(0)
            Else
                Test_Path = Test_Path & "\" & Splitter(I)
            End If
            
ReTest:
            If Dir(Test_Path, vbDirectory) = vbNullString Then
                'Debug.Print "'" & Test_Path & "' does not exist"
                MkDir Test_Path
                'Debug.Print "Making ' " & Test_Path & "'"
                GoTo ReTest
            Else
                'Debug.Print "'" & Test_Path & "' exists"
            End If
        Next I
    End If
    

End Sub

I would HIGHLY RECOMMEND that you test this code out with some dummy data first to fully understand how it works before using it on real data.
Some people may not like the deletion aspect of the above codebase, I have used this myself for years, but if you understand when and how it operates you should not have any issues.

While this code does work, you should probably add further checking and error handling measures to ensure it executes the way you expect it to.
I don't know the full extent of the possible variations of directory paths, filenames etc and so this code doesn't account for unforeseen issues.

At the very least, I hope it gets you started along the path to automate this process (sorry but automatize isn't a real word ;)

regards,
BenR
 
Upvote 0
Booker,

Copy all of the above code blocks into a module and begin the process with the command;
VBA Code:
Check_Files "C:\Desktop\MyFiles"

Or whatever your search directory path is.

I was going to edit this into my post, but apparently there is a 10 minute 'edit' window that I missed
Sorry, I'm new to these boards too ;)

regards,
BenR
 
Upvote 0
Hi Ben,

Thank you so much for replying. Some issues I need to address:

First of all, I mentioned that the files name are "01 - 567567" and so on for simplicity but their names are actually longer than that as we need to identify what's the email about. That's why I don't know if the first part of the codes will identify the subfolders correctly.

Secondly, the subfolders are in a different location from the files folder. Let's say that the files are in C:\Desktop\MyFiles and the subfolders are in C:\Desktop\Folders.

Thirdly, it is possible that the deal doesn't have a folder yet and in that case I'd like it to not move the file and not create a new folder.

Sorry that I forgot to mention all that before. I did try that code with a dummy test and what it did was recognize a subfolder in another folder and copied all the files from the destination folder to the general folder. Let's say I created C:\Desktop\Backup and created subfolder 567567 there, what it did was recognize that subfolder and copied all the files (no matter the file type) from C:\Desktop\Files to C:\Desktop\Backup.

Thanks again!
 
Upvote 0
Booker,

First of all, I mentioned that the files name are "01 - 567567" and so on for simplicity but their names are actually longer than that as we need to identify what's the email about. That's why I don't know if the first part of the codes will identify the subfolders correctly.

Without knowing the specific filename format, it is impossible to write something that deals with all of the possible combinations, I appreciate that you tried to simplify what you were asking, but you can see that this can create some issues when trying to address your requirements. Potentially, a more unified naming convention should be adopted, or you will need to account for each case. I hope my initial codebase at least gives you some ideas on how to achieve this if you have defined naming conventions to follow.

Secondly, the subfolders are in a different location from the files folder. Let's say that the files are in C:\Desktop\MyFiles and the subfolders are in C:\Desktop\Folders.

Looking at the comments within the codebase, you can see I allowed for this with the following lines,
VBA Code:
    ' setup where the archive directory is - maybe a network location?
    ' I'll assume it is the same directory path as the work book - change the following path as required
    ' path should be in a format like "C:\Desktop\MyFiles" or something
    Archive_Path = ThisWorkbook.Path
   
    ' the search_path is handed into the function as an argument
    ' checks the Search path - this path is where the file currently are - maybe different than where you want to archive them
    Confirm_Directory Search_Path

This allows you to nominate 'where' you would like the files to be moved (Archive_Path), but also allows you to nominate 'where' to search for the files via the (Search_Path) string that is handed into the actual function itself.

Thirdly, it is possible that the deal doesn't have a folder yet and in that case I'd like it to not move the file and not create a new folder.

Finally, you could try modifying the Confirm_Directory code as follows;
VBA Code:
Public Function Confirm_Directory(This_Path As String, Optional Create_Directory As Boolean) As Boolean
    ' used to test for directory locations
    ' will make sub directories if required
   
    Dim Splitter() As String
    Dim Test_Path As String
   
    If Dir(This_Path, vbDirectory) = vbNullString Then
   
        Splitter = Split(This_Path, "\")
       
        For I = LBound(Splitter) To UBound(Splitter)
            If I = 0 Then
                Test_Path = Splitter(0)
            Else
                Test_Path = Test_Path & "\" & Splitter(I)
            End If
           
ReTest:
            If Dir(Test_Path, vbDirectory) = vbNullString Then
                'Debug.Print "'" & Test_Path & "' does not exist"
                ' check if we should create a directory
                If Create_Directory = True Then
                    MkDir Test_Path
                    Confirm_Directory = True
                Else
                    ' exit function here without making new directory
                    Confirm_Directory = False
                    Exit Function
                End If
                'Debug.Print "Making ' " & Test_Path & "'"
                GoTo ReTest
            Else
                'Debug.Print "'" & Test_Path & "' exists"
                Confirm_Directory = True
            End If
        Next I
    End If
   
End Function

This takes the additional (optional) argument 'Make_New_Directory' a Boolean value of true / false so you can nominate if it should create a new directory or not.
It will default to false if you do not nominate a value (optional).
The function also returns a Boolean value if the directory exists or not - this is used to NOT copy files if the directory doesn't yet exist.

VBA Code:
Public Sub Check_Files(Search_Path As String, Make_New_Directory As Boolean)

    Dim File_Name As String
    Dim File_Type As String
   
    Dim strFileName As String
    Dim Deal_Name As String
   
    Dim Archive_Path As String
    Dim Target_Path As String
   
    Dim File_Count As Integer
   
    ' setup where the archive directory is - maybe a network location?
    ' I'll assume it is the same directory path as the work book - change the following path as required
    ' path should be in a format like "C:\Desktop\MyFiles" or something
    Archive_Path = ThisWorkbook.Path
   
    ' the search_path is handed into the function as an arguement
    ' checks the Search path - this path is where the file currently are - maybe different than where you want to archive them
    Confirm_Directory Search_Path
   
    ' changes excel's default directory path to the one you want to search
    ChDir Search_Path

    ' assumes .msg files, but could be .pdf files - make changes as needed
    File_Type = Search_Path & "*.msg"

    ' identifies file name within the target directory
    strFileName = Dir(File_Type)
   
    ' cycles through each file within the search directory - will continue until the length of the strFileName = 0 (i.e. no files)
    Do While Len(strFileName) > 0
       
        ' get the sub directory or #deal name
        Deal_Name = Return_SubDirectory_Name(strFileName)
       
        ' test if we have a valid deal name (not a vbnullstring)
        If Len(Deal_Name) > 0 Then
       
            ' update the target_path - the target path will change as the different #deal name subdirectories within the archive path change
            Target_Path = Archive_Path & "\" & Deal_Name
       
            ' checks if THAT target archive path exists - makes one if required - wont copy if required directory doesn't exist
            If Confirm_Directory(Target_Path, Make_New_Directory) = True Then
           
                ' copy required file to the target archive directory
                FileCopy Search_Path & "\" & strFileName, Target_Path & "\" & strFileName
   
                ' delete original copy from search directory
                Kill Search_Path & "\" & strFileName
           
                File_Count = File_Count + 1
            Else
                MsgBox "The required directory," & Chr(10) & Target_Path & Chr(10) & Chr(10) & "doesn't exist - no files moved.", vbCritical, "No Valid Directory"
            End If
       
        End If
       
        ' aquires the next filename in the search directory
        strFileName = Dir
       
    Loop

    Debug.Print "Moved " & File_Count & " file(s)"

End Sub

I hope this will allow you to automate your file management.

regards,
BenR
 
Upvote 0
Hi Ben,

Thanks for replying again. I've already made all the necessary changes but for some reason I can't run the code after copying and pasting it. There's no debug error, it just straight up doesn't run after hitting the play button and it doesn't appear on the macro box either. Do you know what could be the issue?

Thank you.
 
Upvote 0
Booker,

The macro 'Check_Files' accepts two arguments, one of them IS required, one is optional.
Simply hitting the 'play button' wont run the macro (as it requires the Search_Path argument)

If your Search_Path is something like "C:\Users\Me\Desktop" then you would enter this into the immediate window;

VBA Code:
Check_Files "C:\Users\Me\Desktop"

If you want any sub directories created, the starting code would be;

VBA Code:
Check_Files "C:\Users\Me\Desktop", True

You could dig a little deeper and bind this macro to a button of your worksheet.
But this would require you to nominate the Search Path and hand that as an argument to the function call.

Your original post did not define *how* you would trigger this, and that depends on how you would normally access / run the code.

Hope this helps,
BenR
 
Upvote 0

Forum statistics

Threads
1,223,228
Messages
6,170,871
Members
452,363
Latest member
merico17

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top