Excel VBA Course
Excel VBA Course - From Beginner to Expert

200+ Video Lessons
50+ Hours of Video
200+ Excel Guides

Become a master of VBA and Macros in Excel and learn how to automate all of your tasks in Excel with this online course. (No VBA experience required.)

View Course

loop through subfolders to move pdf files

0

Hi  guys,

I need making  this  code also does   loop through the  subfolders .

the  code  just deals  with  main  folder in DATA folder  and  ignores subfolders   ,  the  DATA folder contains folders  and  subfolers. so  what  I  want  the  code implement  for  any  folder is  existed inside  the DATA folder  and  any  subfolder  is  existed within it .

Public Sub Move_Files_To_Subfolders()

    Dim matchFiles As String
    Dim fromFolder As String, toFolder As String
    Dim FSO As Object 'Scripting.FileSystemObject
    Dim FSfromFolder As Object 'Scripting.Folder
    Dim FSfile As Object 'Scripting.File

    matchFiles = "C:\DATA\*_*.pdf"

    fromFolder = Left(matchFiles, InStrRev(matchFiles, "\"))
        Set FSO = CreateObject("Scripting.FileSystemObject")
    Set FSfromFolder = FSO.GetFolder(fromFolder)
    For Each FSfile In FSfromFolder.Files
        If LCase(FSfile.Path) Like LCase(matchFiles) Then
            toFolder = fromFolder & Left(FSfile.Name, InStr(FSfile.Name, "_") - 1) & "\"
            If Not FSO.FolderExists(toFolder) Then FSO.CreateFolder toFolder
            Debug.Print "MOVE " & FSfile.Path, toFolder
            FSfile.Move toFolder
        End If
    Next
End Sub

thanks

Answer
Discuss

Discussion

Hi Maklal. Did you see Willie's recent comments against my Answer? They may help you getting the solution to work. 
John_Ru (rep: 6152) Jun 15, '23 at 2:27 pm
Add to Discussion

Answers

0

Malkal

Revision 07 June 2023 (moved code portion from function to parent procedure)

Here's a simple macro which searched in a named folder then calls a function. That function checks subfolders in the folder and - for each subfolder- lists files and (iteratively) calls itself to find more files and subfolders within. They are printed in VB Project Explorer's Intermediate window.

Public ObjFolder As Object, objSubFile As Object
Public objFso As Object
Public objFldLoop As Object


Sub GetStructure()

    ' call the function to loop through folder and its subfolders
    Set objFso = CreateObject("Scripting.FileSystemObject")
    Set ObjFolder = objFso.GetFolder("C:\DATA\")

    ' loop through this folder
    For Each objSubFile In ObjFolder.Files
        If InStr(objSubFile.Name, ".pdf") > 0 Then
            Debug.Print objSubFile.Path
        End If
    Next objSubFile
    ' call the function to loop through its subfolders (and theirs)
    LoopEachFolder ObjFolder

    ' quit FSO
    Set objFso = Nothing

End Sub


Function LoopEachFolder(fldFolder As Object)

    ' With the subfolders in this folder....
    For Each objFldLoop In fldFolder.subFolders
        ' ...loop through files in this folder
        For Each objSubFile In objFldLoop.Files
            If InStr(objSubFile.Name, ".pdf") > 0 Then
                Debug.Print objSubFile.Path
            End If
        Next objSubFile
        ' ... and run the function on each subfolder found
        LoopEachFolder objFldLoop

    Next objFldLoop

End Function

If you run GetStructure, it will print (in VB Project Explorer's Immediate window) the path/name for all pdfs in your folder and all levels of subfolder. 

You will need to change both lines:

If InStr(objSubFile.Name, ".pdf") > 0 Then

with:

        If InStr(objSubFile.Name, ".pdf") > 0 And InStr(objSubFile.Name, "_") > 0 Then

(since you want files like "*_*.pdf") and each Debug.Print line with your Move code etc..

Revision 1 08 June 2023:

File added. Be sure you check (/correct) the line:

 Set ObjFolder = objFso.GetFolder("C:\DATA\")

to ensure it has a valid folder which contains files with the extension .pdf.

Revision 2 08 June 2023:

To get a case-insensitive (for *.pdf" and *.PDF files etc,), the code need to convert filenames to lowercase- see changes in bold (implemented in the second attached file, Case-insensitive search through folder and all subfolders v0_b ):

Public ObjFolder As Object, objSubFile As Object
Public objFso As Object
Public objFldLoop As Object


Sub GetStructure()

    ' call the function to loop through folder and its subfolders
    Set objFso = CreateObject("Scripting.FileSystemObject")
    Set ObjFolder = objFso.GetFolder("C:\DATA\")

    ' loop through this folder
    For Each objSubFile In ObjFolder.Files
        If InStr(LCase(objSubFile.Name), ".pdf") > 0 Then
            Debug.Print objSubFile.Path
        End If
    Next objSubFile
    ' call the function to loop through its subfolders (and theirs)
    LoopEachFolder ObjFolder

    ' quit FSO
    Set objFso = Nothing

End Sub


Function LoopEachFolder(fldFolder As Object)

    ' With the subfolders in this folder....
    For Each objFldLoop In fldFolder.subFolders
        ' ...loop through files in this folder
        For Each objSubFile In objFldLoop.Files
            If InStr(LCase(objSubFile.Name), ".pdf") > 0 Then
                Debug.Print objSubFile.Path
            End If
        Next objSubFile
        ' ... and run the function on each subfolder found
        LoopEachFolder objFldLoop

    Next objFldLoop

End Function

Hope this helps. If so, please don't forget to mark this Answer as Selected as usual.

Discuss

Discussion

Hi john ,
what does mean this error?
byref argument  type mismatch in this bold word 
 LoopEachFolder ObjFolder
Malkal (rep: 22) Jun 7, '23 at 4:27 pm
Malkal

Firstly I realised that my Answer was incorrect- please see the revised code in Revision 07 June 2023 and use (/ copy) that.

If you put "C:\DATA\*_*.pdf" in the line Set ObjFolder... that would cause an error I think.

If you still get the problem, please check the folder C:\DATA (copied from your question) actually exists and that the function (not sub) is called  LoopEachFolder.
John_Ru (rep: 6152) Jun 7, '23 at 5:23 pm
the  error  is  gone  , but  doesn't  do  anything whether  in  main folder  or  subfolder !
Malkal (rep: 22) Jun 7, '23 at 6:03 pm
It's very late here but did you check in the Intermediate window? Should be a list a full paths for each pdf. Change Debug.Print for MsgBox if you're not using the Intermediate window normally
John_Ru (rep: 6152) Jun 7, '23 at 6:11 pm
yes it's  empty , doesn't  show  anything in Intermediate window.
Malkal (rep: 22) Jun 7, '23 at 6:21 pm
Are there pdf files there? Try another folder please.

You did put ALL my code into a Module, right? 
John_Ru (rep: 6152) Jun 7, '23 at 6:27 pm
Are there pdf files there?
yes  and  the  orginal  code  works  with  them .
Try another folder please.
unfortunately   the same  result.
You did put ALL my code into a Module, right? 
surely   
Malkal (rep: 22) Jun 7, '23 at 6:49 pm
Malkal. Not sure what you're doing but it works fine for me. I've revised my Answer to attach the file- please run GetStructure from there.

(Oops! I'd added the wrong file but now added the correct one)

IMPORTANT: once you have the code running correctly and Debug.Printing file names, take care adding your "move". Use a different destination (not C:\DATA) in which to create new folders and move files to (or VBA may get lost in a loop since you're changing the structure of the folder you're running through). Move them back to C:\DATA later if you need.
John_Ru (rep: 6152) Jun 8, '23 at 1:24 am
Malkal. Not sure what you're doing but it works fine for me
this is really odd and disappointed !
I  change  path  and  drive to
("E:\TextFolder2023\")
but  doesn't  change  any thing , I tested original  code  with  your  file  works without  any problem.
I  don't  understand this 
take care adding your "move"
Malkal (rep: 22) Jun 8, '23 at 4:19 am
Malkal. Have your pdf files got the extension .PDF? If so, Instr will not find them (with search ".pdf") since it defaults to a binary comparison. You can fix it (and get a case-insensitive search) by changing the decision lines to:

        If InStr(LCase(objSubFile.Name), ".pdf") > 0 Then

If I get time later I will add this to my Answer.

When I said "take care adding your "move"", I meant that it's a bad idea to move files within a structure you are searching. Move them outside for safety!
John_Ru (rep: 6152) Jun 8, '23 at 8:37 am
yes it  works  but  just  within  main  folder, doesn't  happen  any  thing in  subfolders  despite of  showing in Intermediate window .
Malkal (rep: 22) Jun 8, '23 at 9:48 am
Did you change both lines correctly to include LCase( ) on the object?
John_Ru (rep: 6152) Jun 8, '23 at 11:37 am
you  mean like this?

 If InStr(LCase(objSubFile.Name), ".pdf") > 0 And InStr(objSubFile.Name, "_") > 0 Then

the  problem  is  showing in  Intermediate window without happen any  thing inside directory.
this  is  what  show me in  Intermediate window

C:\TextFolder2023\ATRS_87659000.PDF

C:\TextFolder2023\LSDRTR_654100009.PDF
Malkal (rep: 22) Jun 8, '23 at 12:55 pm
Malklal. That is exactly what is meant to happen in my code! The command Debug.Print simply prints something in the Intermediate window, in this case the path and filenames of files like "*_*.pdf" (with the LCase changes)..

I used it to show that the code iterates down the subfolder. Your job is to chnage that print code to do what you want with the files found (and I suggested you move them to anopther directory.

I'll revise my Answer again (not sure why the code got messed up) and to add another file.
John_Ru (rep: 6152) Jun 8, '23 at 1:03 pm
Malkal. Please try SECOND file attaced to my newly revised Answer.
John_Ru (rep: 6152) Jun 8, '23 at 1:19 pm
thanks for your efforts . sorry, it doesn't work any thing whether in main folder or subfolder until previous file .
I barely  lost  my  mind , every  things fine  for  you  , but for  me not !
bad luck!!!
Malkal (rep: 22) Jun 8, '23 at 2:05 pm
Malkal. Did you try my second file without adding "_" ir get someone else to try it? It works perfectly for me but I will try again when I get home. 
John_Ru (rep: 6152) Jun 8, '23 at 2:48 pm
yes I  did  it,
is  it  problem  from  reader acrobat , i don't  have  in laptop  but  show by  microsoft Edge  or  the  version office  is problem?
Malkal (rep: 22) Jun 8, '23 at 3:03 pm
just  to  inform  you  the  original  code  shows  this  in in  Intermediate window
C:\TextFolder2023\ATRS_87659000.PDF  C:\DATA\ATRS\

C:\TextFolder2023\LSDRTR_654100009.PDF C:\DATA\LSDRTR\
that supposes to  do  your  new  version too .
Malkal (rep: 22) Jun 8, '23 at 4:03 pm
You said "is  it  problem  from  reader acrobat , i don't  have  in laptop  but  show by  microsoft Edge... " but they are not involved in the macro. 

On "... or  the  version office  is problem?", I have only Microsoft 365 now but there's nothing in the code which shouldn't work on 2019 (I made the original code years ago when I had 2019).
John_Ru (rep: 6152) Jun 8, '23 at 4:47 pm
I don't understand how you get an output like
C:\TextFolder2023\ATRS_87659000.PDF  C:\DATA\ATRS\

since the bold bit is a folder name (without the *_*.pdf filename).

If I run the macro GetStructure in my second file "Case-insensitive search through folder and all subfolders v0_b.xlsm" but point it to one of my foldes using:  
    Set ObjFolder = objFso.GetFolder("E:\Documents\Spreadsheets\TeachExcel files\")

then this gets printed in the Immediate window:    
E:\Documents\Spreadsheets\TeachExcel files\Project Timeline.pdf
E:\Documents\Spreadsheets\TeachExcel files\Scorecard.pdf
E:\Documents\Spreadsheets\TeachExcel files\Opening other files\1.pdf
E:\Documents\Spreadsheets\TeachExcel files\Opening other files\2.pdf
E:\Documents\Spreadsheets\TeachExcel files\Opening other files\3.pdf
E:\Documents\Spreadsheets\TeachExcel files\Professor Excel files\Keyboard_Shortcuts_Package.pdf
E:\Documents\Spreadsheets\TeachExcel files\Test files\Project Timeline.pdf

where you can see *.pdf files in the first folder follwed by some in subfolders (in bold).

I'm not sure I can help further, sorry.
John_Ru (rep: 6152) Jun 8, '23 at 5:00 pm
I don't understand how you get an output like
Select All
C:\TextFolder2023\ATRS_87659000.PDF  C:\DATA\ATRS\
this  what  really  happened  for  me based  on  original code then this gets printed in the Immediate window:     Select All
E:\Documents\Spreadsheets\TeachExcel files\Project Timeline.pdf
E:\Documents\Spreadsheets\TeachExcel files\Scorecard.pdf
E:\Documents\Spreadsheets\TeachExcel files\Opening other files\1.pdf
E:\Documents\Spreadsheets\TeachExcel files\Opening other files\2.pdf
E:\Documents\Spreadsheets\TeachExcel files\Opening other files\3.pdf
E:\Documents\Spreadsheets\TeachExcel files\Professor Excel files\Keyboard_Shortcuts_Package.pdf
E:\Documents\Spreadsheets\TeachExcel files\Test files\Project Timeline.pdf
yes  this  what  shows  me based on  your  files. I'm not sure I can help further, sorry. no problem ,  I  appreciate for  your  effort, despite  doesn't  solve  my problem  at  least  on  my  laptop. I  will test  it  in  another laptop. the  EXCEL   could  causes odd  things in different pc,laptops this make  EXCEL is not  possible  depend  on the  programming .    
Malkal (rep: 22) Jun 8, '23 at 5:34 pm
@John_Ru
Hi John,
I copied your code (Rev 7 June 2023) and put it into a blank 2016 workbook.
The only line I had to modify was:
Set ObjFolder = objFso.GetFolder("C:\DATA\")
changing C:\DATA\ to a valid path on my laptop.
When I ran the macro it ran without any hiccups (errors) and grabbed all of the "pdf" files.
If MalKal's file resides on "C:\" then MalKal may need to add this line at the top of the macro: ChDir "E:\TextFolder2023\"
Except for this possibility, your code runs just fine.

Cheers   :-)
WillieD24 (rep: 557) Jun 13, '23 at 8:39 pm
@Willie- thanks very much for taking the time to test my code and confirming that it works as I expected it.

@Maklal- hope you've got the code to work for you. If you need to impelement Willie's suggestion above, I think you'll need to make it:
ChDir  "C:\DATA\"
(rather than to "E:\TextFolder2023\").

That could be applicable also to the second file (to give the case-insensitive search you seem to need).
John_Ru (rep: 6152) Jun 14, '23 at 2:55 am
sorry  for  delaying ,I  m not  sure  if  I  understood guys,  
what  happens  for  this  line  when  add  the  same directory above ?
Set ObjFolder = objFso.GetFolder ("C:\DATA\")
Malkal (rep: 22) Jun 27, '23 at 12:17 pm
Malkal 

I'm not sure what you mean by your comment above, sorry. If the directory C:\DATA exists then the second file should print out the path/filename of each pdf there (if any).

BTW I just got my netbook working and it worked fine with that second file.
John_Ru (rep: 6152) Jun 27, '23 at 12:49 pm
I'm talking  about  willie 's  suggestion 
If MalKal's file resides on "C:\" then MalKal may need to add this line at the top of the macro: ChDir "E:\TextFolder2023\"
so  I  should  put  this  above
ChDir "C:\DATA\"
like this
ChDir "C:\DATA\"

Sub GetStructure()     ' call the function to loop through folder and its subfolders     Set objFso = CreateObject("Scripting.FileSystemObject")     
    Set ObjFolder = objFso.GetFolder("C:\DATA\")
that  doesn't  work  and  give procerdure outside
Malkal (rep: 22) Jun 27, '23 at 1:02 pm
I didn't use Willie's suggestion and you shouldn't need to. Please try my seconf file as I sent it (download it again if necessary). As I added above, it worked fine on my laptop (a very low spec netbook).

Does C:\DATA exist? Did you try
Set ObjFolder = objFso.GetFolder("C:\")
with ChDir?
John_Ru (rep: 6152) Jun 27, '23 at 1:13 pm
sorry I thought there is alternative to solve my problem , but seem the problem is still continuing .
Malkal (rep: 22) Jun 27, '23 at 2:53 pm
Sorry but I meant to say Did you try,,, without ChDir?

Did you try C:\? 

There may be other alternartive for your problem but my Answer works for me (on a couple of versions of Windows and Excel) and for Willie too. Sorry but I don't know why it doesn't work for you.

Did you ask a friend to try the file (having placed a .pdf file)?


John_Ru (rep: 6152) Jun 27, '23 at 3:16 pm
Did you try C:\? 
yes  and  gives  error  permission  denied in  this  line 
  For Each objSubFile In objFldLoop.Files

Did you ask a friend to try the file (having placed a .pdf file)?
in reality  no ,  but  I  tested  with  three laptops and  different  versions 2010,2013,2019  there  is  no  changing in  the  result !
Malkal (rep: 22) Jun 28, '23 at 1:58 pm
Hi again Maklal

I think "error  permission  denied" will arise if the search include a root or protected folder (and C:\ will do that sorry).

I tried C:\Users\ and got the same error (for the subfolder ApplicationData) but not before the Immediate Window displayed several pdf files.

If the second file Case-insensitive search through folder and all subfolders v0_b.xlsm does not work on C:\Users\ or a subfolder of C:\Data\ then I don't know what to suggest. I really don't have more time to spare on this, sorry.
John_Ru (rep: 6152) Jun 28, '23 at 6:20 pm
Add to Discussion


Answer the Question

You must create an account to use the forum. Create an Account or Login