|
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"
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!
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:2018-Dec 08, Sat, 10-43 pmThe prefix (psPrefix) at the beginning of the filename is "Cats", followed by an underscore for separation.
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.
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!
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!
* if you have problems, email me. I will try to help and then expand these instructions.
Once you have saved this code in a module, to run this, without writing any more code:
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.
The symbols you can use in the format code parameter for the Date/Time data type are listed in help under Custom formats.
' 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
Click
HERE
to download the zipped BAS file containing the code above.
(4 kb, unzips to a BAS module file)