rename a folder of files MVP logo Ms Access Gurus
If you like this site, please consider giving a donation to help balance the cost. Thank you.

Quick Jump

VBA » File » Loop and Rename

Loop through files in a folder. Rename to include modification date, time, and subject. Help identify pictures and use for documents too.

These are pictures of cats sleeping. The new filename includes the date as YYMMDD and then the day of week abbreviation. Time is HHMM on 24-hour clock. The format code is "yymmdd_ddd_hhnn"

Goto Top  

Examples

The two picture files were automatically renamed. Before running, the file names were:

The new filenames include the date/time (yymmdd) of the photo, the day of week, and the time:

Now when you look at the file names, you can see when. These 2 pictures are 6 years apart, which is now easy to see. 121205 (yymmdd) is December 12, 2012 and 181202 is December 12, 2018. 1030 and 0503 are times ... 1030 is 10:30 am and 0503 was an early morning picture of cats sitting sweetly together on a chair.

Hope this gets you on on the road to organizing your pictures.

This code can run from Access ... or Excel ... or Word ... or PowerPoint ... or from VBA in any other Microsoft Office application. There is nothing in it that requires Access. It is pure VBA!

Goto Top  

How to call:

These are statements you can modify to run from code, or paste into the debug window and customize. Substitute c:\myPath with the full path to the files you wish to rename.

Beginners: use this version! Rename files with default format for date/time, and be prompted for each change:

Call LoopFolder_RenameFiles("c:\myPath", false)

Automatically rename all files in folder using default settings. Skip prompting for each change, so no message till it is done:

Call LoopFolder_RenameFiles("c:\myPath", true)


Automatically rename all JPG (psMask) files in specified folder (psPath) Skip prompting (pBooSkipPromptEachFile = True). The file date/time (psFormatCode), will appear like
               2018-Dec 08, Sat, 10-43 pm 
The prefix (psPrefix) at the beginning of the filename is "Cats", followed by an underscore for separation.

Call LoopFolder_RenameFiles("c:\myPath\", true, "yyyy-mmm dd, ddd, hh-nn am/pm", "*.jpg" , "Cats_")

Sample new file name:

Cats_2018-2018-Dec 08, Sat, 10-43 pm~-DSC06236.JPG



Put back to original file name. Delete extra information with date/time and category for all files in the folder, and skip prompting for each change (pBooSkipPromptEachFile is True).:

Call LoopFolder_RenameFiles("c:\myPath", True, "")

Goto Top  

Logic

Note: this is explained for a developer. If that is not you, then look at the examples to see how to call it, and skip to the Beginners section to use it.

Loop through all the files in a folder. Save each name to an array. Pre-dimension the array for the maximum number of files. ReDim Preserve when done for real number read.

Read the date/time modified using the FileDateTime VBA function. Convert the file date/time to a string using the passed format code (Default is "yymmdd_ddd_hhnn" if not specified. Access uses "n" for miNute.) so it can be included in a filename.

Add the extra information (specified category and file date/time), followed by a separator of "~‐" to the beginning of the file name. If the separator is already in the filename, the extra information previously added is removed, and the adjusted name does not include extra information.

If a format code for date/time of "" is passed, then any extra information previously added will be removed and the file name will be put back to its original value.

If a format code is specified, or the default value is used, then the new filename will begin with the category, then a string representing the date/time, then a separator of "~‐", and then the original file name.

By default, the date will use a format code of "yymmdd_ddd_hhnn" so when files are sorted alphabetically, they will also be chronological. The text at the beginning of the name is the category: "p" is for "picture" and is the default since it is better to start a filename with a letter than a number.

Note

The specified format code could be checked for illegal characters in a file name, but to keep it simpler, this is not done, so don't send any illegal characters in the format code argument.

There could be an option for extra information to be before or after the filename, but to keep it simple and for the order of filenames to be by your code, it is at the beginning. You could easily switch the extra information to be at the end before the file extension.

You could add a parameter for a folder path to copy renamed files to, and leave original files as they are.

Path wants to be terminated with \. If you fail to include the trailing backslash, it will be added.

BACKUP DATA your folder before running this the first time, just in case results are not what you want. Hopefully it will work as expected for you, and you can continue to organize!

Beginners

Are you excited by the possibilities? Then give this a go -- it is highly useful and can get you started organizing your files. I've tried to make it easy. Optional parameters are there for those who want more. To start, you can just send a path!

How do you get a path?

then edit to run with that path -- and presto! all files renamed.

It is a good idea to start with a copy of a folder of files till you get what you want to do figured out by running it and looking at the results.

Don't let the apparent complexity of this code scare you off from trying it!

  1. Create a general module
  2. , paste the code at the bottom
  3. , from the menu bar, choose: Debug > Compile Database
  4. and then Save.
When prompted for a name, use mod_LoopFolder_RenameFiles or something else logical. Once it compiles without any issues, you are ready to run.

* if you have problems, email me. I will try to help and then expand these instructions.

Run

Once you have saved this code in a module, to run this, without writing any more code:

  1. Press Ctrl-G to open the Debug/Immediate window
  2. Paste in one of the examples,
  3. modify for your path and, optionally, specify additional parameters if you want to get fancy.
  4. Then press ENTER to run!

Developers

You may want to modify this code to use results from ListFiles instead of looping to get filenames for a path and maybe also used extended properties to rename with more. If you have a table or query with a list of path\files, you can automatically rename many more files.

Parameters

Optional:

Goto Top  

Reference

The symbols you can use in the format code parameter for the Date/Time data type are listed in help under Custom formats.

Docs / Office VBA Reference / Access / Concepts / Data types / Date/Time

help: Date/Time data type (Format property)

Goto Top  

Code

' http://msaccessgurus.com/VBA/Code/File_LoopRenameDate.htm
' bas_vba_File_LoopRename_s4p
'*************** Code Start *****************************************************
' Purpose  : Loop through files in a folder, rename with subject, date and time modified
' Author   : crystal (strive4peace)
' License  : below code
' Code List: www.MsAccessGurus.com/code.htm
'--------------------------------------------------------------------------------
'                              Module declaration
'--------------------------------------------------------------------------------
' --------- Scripting.FileSystemObject
Private moFile_fso As Object 
'--------------------------------------------------------------------------------
'                              RUN LoopFolder_RenameFiles
'--------------------------------------------------------------------------------
Sub run_LoopFolder_RenameFiles() 
'220102 strive4peace

   'CALLS
   '  LoopFolder_RenameFiles

   'CLICK HERE
   'Press F5 to Run!     ... after CUSTOMIZE!
   'turn on Immediate window to see results
   
   Dim sPath As String _ 
      ,sPrefix As String _ 
      ,sMsg As String 
      
   sPrefix =  "catSleep_"      '----------- CUSTOMIZE!
   sPath =  "E:\p\pic_catsSleep"    '----------- CUSTOMIZE!
   
   '~~~~~~~~~~~~~~~~~~~~~ Call LoopFolder_RenameFiles
   'Call LoopFolder_RenameFiles
   '  send sPath for path
   '  , true for SkipPromptEachFile
   '  , skip FormatCode and Mask so defaults will be used
   '  , specify prefix to be sPrefix
   '  , GET messageback
   'ignore function return for number of changed files
   Call LoopFolder_RenameFiles( _ 
      sPath,True,,,sPrefix,sMsg) 
   '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   
   Debug.Print sMsg 
   
   sMsg = sMsg & vbCrLf & vbCrLf &  "Open folder?"
   If MsgBox(sMsg,vbYesNo, "Done. Open Folder?") = vbYes Then 
      Call Shell( "Explorer.exe" &  " " & sPath,vbNormalFocus) 
   End If 
   
End Sub 
'--------------------------------------------------------------------------------
'                              LoopFolder_RenameFiles
'--------------------------------------------------------------------------------
Function LoopFolder_RenameFiles(psPath As String _ 
   ,Optional pBooSkipPromptEachFile As Boolean = True _ 
   ,Optional psFormatCode As String =  "yymmdd_ddd_hhnn" _ 
   ,Optional psMask As String =  "*.*" _ 
   ,Optional psPrefix As String =  "p" _ 
   ,Optional ByRef psRETURNMsg As String _ 
   ) As Integer 
' s4p 161005, 181207, 220101,2
   'PARAMETERS
   '   psPath is the path to use
   '   Optional:
   '   pBooSkipPromptEachFile, Boolean, Default = true
   '   psFormatCode, String, default = "yymmdd_ddd_hhnn"
   '   psMask, String, file specification to match. Default = "*.*"
   '   psPrefix, String, characters to put at beginning of filename. Default = "p" _
   '   psRETURNMsg, String, message to send back to calling program

   'CALLS
   '  GetArrayFilenames

   On Error GoTo proc_Err 
 
   Dim aFilename() As String 
   
   Dim iFile As Integer _ 
      ,iPos As Integer _ 
      ,iAnswer As Integer _ 
      ,iCount As Integer _ 
      ,iCountDone As Integer _ 
      ,sFilename As String _ 
      ,sAdjustedName As String _ 
      ,sNewFilename As String _ 
      ,sPathFile As String _ 
      ,sExtraInfo As String _ 
      ,sNewPathFile As String _ 
      ,sSeparator As String _ 
      ,sMsg As String _ 
      ,booDo As Boolean 
      
   sSeparator =  "~-"

   If Right(psPath,1) <>  "\" Then 
      psPath = Trim(psPath) &  "\"
   End If 
   
   iCount = 0 
   iCountDone = 0 

   '---------------------------- array of filenames
   aFilename = GetArrayFilenames(psPath,psMask) 
   
   For iFile = LBound(aFilename) To UBound(aFilename) 
      iCount = iCount + 1 
      sFilename = aFilename(iFile) 
      'see if the file has already been renamed
      iPos = InStr(sFilename,sSeparator) 
      If iPos > 0 Then 
         'strip previous extra information
         sAdjustedName = Mid(sFilename,iPos + Len(sSeparator)) 
      Else 
         sAdjustedName = sFilename 
      End If 
      
      sPathFile = psPath & sFilename 
      If psFormatCode <>  "" Then 
         sExtraInfo = psPrefix _ 
         & Format(FileDateTime(sPathFile),psFormatCode) _ 
         & sSeparator 
      Else 
         sExtraInfo =  ""
      End If 
      
      sNewFilename = sExtraInfo & sAdjustedName 
      sNewPathFile = psPath & sNewFilename 
      
      sMsg = Format(iFile, "000") &  ". Rename " _ 
         & sFilename &  " to " & sNewFilename &  "?"
         
      Debug.Print 
      Debug.Print sMsg; 
      
      If pBooSkipPromptEachFile = True Then 
         booDo = True 
      Else 
         iAnswer = MsgBox(sMsg,vbYesNoCancel, "Rename this file?") 
         If iAnswer = vbYes Then 
            booDo = True 
         ElseIf iAnswer = vbNo Then 
            Debug.Print  " -- SKIP"; 
            booDo = False 
         ElseIf iAnswer = vbCancel Then 
            GoTo proc_Exit 
         End If 
      End If 
      
      If booDo Then 
         If sPathFile <> sNewPathFile Then 
            Name sPathFile As sNewPathFile 
            Debug.Print  " --> Done"; 
            iCountDone = iCountDone + 1 
         Else 
            Debug.Print  " -- NO CHANGE"; 
         End If 
      End If 

      
   Next iFile  'filename
   Debug.Print 
   
   
proc_Exit: 
   On Error Resume Next 
   psRETURNMsg =  "Done. Looped through " _ 
            & Format(iCount, "#,##0") _ 
            &  " File" & IIf(iCount <> 1, "s", "") _ 
         & vbCrLf &  "Renamed " _ 
            & Format(iCountDone, "#,##0") _ 
            &  " File" & IIf(iCountDone <> 1, "s", "") _ 
         & vbCrLf &  "in path:" _ 
         & vbCrLf & Space(3) & psPath 
   
   LoopFolder_RenameFiles = iCountDone 
   Exit Function 
  
proc_Err: 
   MsgBox Err.Description _ 
       ,, "ERROR " & Err.Number _ 
        &  "   LoopFolder_RenameFiles"

   Resume proc_Exit 
   Resume 
End Function 

'--------------------------------------------------------------------------------
'                              GetArrayFilenames
'--------------------------------------------------------------------------------
Function GetArrayFilenames( _ 
   ByVal psPath As String _ 
   ,Optional psMask As String =  "*.*" _ 
   ,Optional pbRETURNpathGood As Boolean _ 
   ) As Variant 
's4p 181208, 190717, 220102
'read filenames from a folder

   'PARAMETERS
   '  psPath is path to look in
   '  psMask is what to look for (ie: *.* or specific like *.jpg)
   '  pbRETURNpathGood. Return path test
   '     True = Path Good
   '     False = Bad Path
   'RETURN
   '  filename OR unallocated array
   '
   'CALLS
   '  GetCountFiles
   '
   'USES
   '  Scripting.FileSystemObject

   '
   On Error GoTo proc_Err 

   Dim sPathFile As String _ 
     ,sFilename As String _ 
     ,nCount As Long _ 
     ,nFiles As Long 
   
   Dim aFilename() As String 
   
   'initialize return value to be unallocated array
   'LBound = 0, UBound = -1
   GetArrayFilenames = Split(vbNullString) 
      
   psPath = Trim(psPath) 
   If Right(psPath,1) <>  "\" Then 
      psPath = psPath &  "\"
   End If 
   
   nFiles = GetCountFiles(psPath)  '-1=Bad Path
   
   If nFiles < 0 Then 
      pbRETURNpathGood = False 
   Else 
      pbRETURNpathGood = True 
   End If 
   
   'no files
   If Not nFiles > 0 Then 
      Exit Function 
   End If 
   
   'avoid ReDim in the loop for better performance
   'even though mask may knock some of them out
   ReDim aFilename(1 To nFiles) 
   
   nCount = 0 
   
'   ' ---------------------------- Dir()
'   'get first file matching mask
'   sFilename = Dir(psPath & psMask)
'
'   'add to a array of filenames
'   Do While sFilename <> ""
'      If psMask = "*.*" Or sFilename Like psMask Then
'         sPathFile = psPath & sFilename
'         'this has problem with unicode characters in name
'         If (GetAttr(sPathFile) And vbDirectory) <> vbDirectory Then
'            nCount = nCount + 1
'            aFilename(nCount) = sFilename
'         End If
'      End If
'
'       'get next filename
'      sFilename = Dir()
'   Loop

   ' ---------------------------- Scripting.FileSystemObject
   'better at getting long complicated names than Dir
   For Each moFile_fso In CreateObject( "Scripting.FileSystemObject").GetFolder(psPath).Files 
      sFilename = moFile_fso.Name 
      If psMask =  "*.*" Or sFilename Like psMask Then 
         nCount = nCount + 1 
         aFilename(nCount) = sFilename 
      End If 
   Next moFile_fso 

   'see if array elements are less due to mask
   If nCount <> 0 Then 
      'path was valid but no files
      If nCount <> nFiles Then 
         'number found less than in folder
         ReDim Preserve aFilename(1 To nCount) 
      End If 
      'return filename array
      GetArrayFilenames = aFilename 
   End If 

proc_Exit: 
   On Error Resume Next 
   Exit Function 
  
proc_Err: 
   MsgBox Err.Description _ 
       ,, "ERROR " & Err.Number _ 
        &  "   GetArrayFilenames"

   Resume proc_Exit 
   Resume 
End Function 
'--------------------------------------------------------------------------------
'                              alternate run_Time_LoopFolder_RenameFiles
'--------------------------------------------------------------------------------
'  Timer Function
'  https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/timer-function
'  seconds elapsed since midnight
Sub run_Time_LoopFolder_RenameFiles() 
's4p 220101
   'CALLS
   '  LoopFolder_RenameFiles

   Dim sgTimer As Single 
   sgTimer = Timer 
 
   Dim sPath As String _ 
      ,sPrefix As String _ 
      ,sgDiff As Single 
      
   sPrefix =  "catSleep_"      '----------- change me!
   sPath =  "E:\p\pic_catsSleep"    '----------- change me!
   
   Call LoopFolder_RenameFiles(sPath,True,,,sPrefix) 
   If Timer() < sgTimer Then 
      'assume total time is less than one day
      sgDiff = 60 * 60 * 24 - sgTimer + Timer 
   Else 
      sgDiff = Timer - sgTimer 
   End If 
   Debug.Print  "> " & Format(sgDiff, "#,##0.####") _ 
      &  " seconds to execute"
   
End Sub 

'--------------------------------------------------------------------------------
'                              GetCountFiles
'  duplicated here as a Private function
'--------------------------------------------------------------------------------
' http://msaccessgurus.com/VBA/Code/File_CountFiles.htm
Private Function GetCountFiles(psPath As String) As Long 
'strive4peace
'uses Late Binding. Reference for Early Binding:
'  Microsoft Scripting Runtime
   'PARAMETER
   '  psPath is folder to get the number of files for
   '     for example, c:\myPath
   ' Return: Long
   ' -1 = path not valid
   ' 0 = no files found, but path is valid
   ' 99 = number of files where 99 is some number
   
   'inialize return value
   GetCountFiles = -1 
   'skip errors
   On Error Resume Next 
   'count files in folder of FileSystemObject for path
   With CreateObject( "Scripting.FileSystemObject") 
      GetCountFiles = .GetFolder(psPath).Files.Count 
   End With 
End Function 


' LICENSE
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Use at your own risk.
'   ~ crystal (strive4peace)  www.MsAccessGurus.com
'*************** Code End *******************************************************
' Made with Color Code add-in

Goto Top  

Download

Click HERE to download the zipped BAS file containing the code above.
(4 kb, unzips to a BAS module file)  

Goto Top  

Backstory

I love taking pictures! But the filenames created by my camera aren't very descriptive. I generally run this code after moving pictures from my camera to the PC.

Goto Top  

Share

Share with others ... here's the link to copy:
https://MsAccessGurus.com/VBA/Code/File_LoopRenameDate.htm