VBA producing most recently modified .XLS file in a folder - vba

What VBA code can I use to use a folder path displayed in a cell to retrieve the most recently modified .xls file within that folder? So far, I have filenames showing but not the correct files:
Function GetFileNames(ByVal FolderPath As String) As Variant
Dim Result As Variant
Dim i As Integer
Dim MyFile As Object
Dim MyFSO As Object
Dim MyFolder As Object
Dim MyFiles As Object
Set MyFSO = CreateObject("Scripting.FileSystemObject")
Set MyFolder = MyFSO.GetFolder(FolderPath)
Set MyFiles = MyFolder.Files
ReDim Result(1 To MyFiles.Count)
i = 1
For Each MyFile In MyFiles
Result(i) = MyFile.Name
i = i + 1
Next MyFile
GetFileNames = Result
End Function

I think that what you are looking for is something like the selected answer for this question.
You could adapt the code to fit your specific needs of passing the argument inside the like the function below. Note that the argument directory must include the backward slash at the end (eg. "C:\Users\").
Function NewestFile(Directory As String) As String
'PURPOSE: Get the newest file name from specified directory
Dim FileName As String
Dim MostRecentFile As String
Dim MostRecentDate As Date
Dim FileSpec As String
'Specify the file type, if any
FileSpec = "*.xls"
FileName = Dir(Directory & FileSpec)
If FileName <> "" Then
MostRecentFile = FileName
MostRecentDate = FileDateTime(Directory & FileName)
Do While FileName <> ""
If FileDateTime(Directory & FileName) > MostRecentDate Then
MostRecentFile = FileName
MostRecentDate = FileDateTime(Directory & FileName)
End If
FileName = Dir
Loop
End If
NewestFile = MostRecentFile
End Function
EDIT: For more flexibility, you can also add the option (like in PeterT's revised answer) to search for another type of file with the optional FileSpec argument like in the alternative function below. For this function, if you don't provide any value for FileSpec, it will look at all files.
Function NewestFile(ByVal Directory As String, Optional ByVal FileSpec As String = "*.*") As String
'PURPOSE: Get the newest .xls file name from
Dim FileName As String
Dim MostRecentFile As String
Dim MostRecentDate As Date
'Specify the file type, if any
FileName = Dir(Directory & FileSpec)
If FileName <> "" Then
MostRecentFile = FileName
MostRecentDate = FileDateTime(Directory & FileName)
Do While FileName <> ""
If FileDateTime(Directory & FileName) > MostRecentDate Then
MostRecentFile = FileName
MostRecentDate = FileDateTime(Directory & FileName)
End If
FileName = Dir
Loop
End If
NewestFile = MostRecentFile
End Function
Speed issue: Dir Function vs FileSystemObject
In terms of speed, if the folder you want to look at contains a small number of files, the 2 methods will give you the same results in roughly the same amount of time. However, if you have a lot of files in that folder, using the Dir Function approach instead of the FileSystemObject should speed up greatly the execution of your macro. I haven't tested it, but that seems to be what was concluded from the answers in this question.

You just need to check the DateLastModified timestamp of each file in the folder. A quick check to see if it's the most recent will "sort" it to the top.
Option Explicit
Sub test()
Debug.Print "most recently modified file is " & GetNewestModifiedFilename("C:\Temp")
End Sub
Function GetNewestModifiedFilename(ByVal folderPath As String, _
Optional fileType As String = "xls*") As String
Dim MyFSO As Object
Dim MyFolder As Object
Dim MyFiles As Object
Set MyFSO = CreateObject("Scripting.FileSystemObject")
Set MyFolder = MyFSO.GetFolder(folderPath)
Set MyFiles = MyFolder.Files
Dim mostRecentFilename As String
Dim mostRecentTimestamp As Date
Dim MyFile As Object
For Each MyFile In MyFiles
Debug.Print MyFile.Name & ", modified " & MyFile.DateLastModified
If Mid(MyFile.Name, InStrRev(MyFile.Name, ".") + 1) Like fileType Then
If MyFile.DateLastModified > mostRecentTimestamp Then
mostRecentFilename = MyFile.Name
mostRecentTimestamp = MyFile.DateLastModified
End If
End If
Next MyFile
GetNewestModifiedFilename = mostRecentFilename
End Function

Related

VBA - Copy Mutiple File (After Download 1..2..3..) by Count into a Folder

I have need help to copy multiple file into a folder after download.
The file after download default rename as:
Branch_A.xlsx
Branch_A (1).xlsx
Branch_A (2).xlsx
Here code normally i use but this code only copy one file to a folder.
I need the code can capture words "Branch_A" then count file and copy to folder Branch_A. The count file is fix 3 its will come 4..5..6..
Sub down1()
'RENAME FILE DOWNLOAD BY BRANCHES
Dim Ws As Worksheet
Dim FromPath As String
Dim ToPath As String
Set Ws = ThisWorkbook.Worksheets("Path_Down1")
'FROM DOWNLOAD - C:\Users\Downloads\
FromPath = Ws.Range("E11").Value
'TO FOLDER - D:\Inbound\Branch_A\
ToPath = Ws.Range("F11").Value
Ws.Activate
FileCopy FromPath, ToPath
End Sub
I search few website and found that the code can count the file base on extention but i don't know how to edit to count by name and copy to folder. Here sample code:
Sub sample()
Dim FolderPath As String, path As String, count As Integer
FolderPath = "C:\Documents and Settings\Santosh\Desktop"
path = FolderPath & "\*.xls"
Filename = Dir(path)
Do While Filename <> ""
count = count + 1
Filename = Dir()
Loop
Range("Q8").Value = count
'MsgBox count & " : files found in folder"
End Sub
Thanks for your help.
Is the code below something you're looking for? This is what I could come up with what made sense to me. If not please provide more information as to what the issue is.
Sub Down1()
Dim FromFolder As String, ToFolder As String
Dim FromPath As String, ToPath As String, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Path_Down1")
FromFolder = ws.Range("E11").Value
ToFolder = ws.Range("F11").Value
Filename = Dir(FromFolder & "\*.xlsx")
Do While Filename <> ""
If InStr(Filename, "Branch_A") > 0 Then
FromPath = FromFolder & "\" & Filename
ToPath = ToFolder & "\" & Filename
FileCopy FromPath, ToPath
End If
Filename = Dir()
Loop
End Sub

Capture directory value found with wildcard

Is there a way of storing the directory found when using a wildcard? For example, if I have code that checks whether a directory exists:
Public Function DirectoryFinder(PartialFolderName As String)
Dim FilePath As String
If Dir(CurrentProject.Path & "\DataFolder\" & PartialFolderName & "*", vbDirectory)<>"" Then
'FilePath = ???
End If
End Function
Where the current project resides in C:\Folder and the desired full filepath is C:\Folder\DataFolder\PartialFolderName12345.
Is there a way to capture the directory found by the Dir() function within the FilePath variable? If I define FilePath as the following, I don't believe it captures the directory found:
FilePath=CurrentProject.Path & "\DataFolder\" & PartialFolderName & "*"
Rather, it sets FilePath equal to the string "C:\Folder\DataFolder\PartialFolderName*", which doesn't work for what I need.
What I want to be able to capture is the full "C:\Folder\DataFolder\PartialFolderName12345"
Something like this?
Sub Test()
Dim MyPath As String
MyPath = DirectoryFinder("SomeFolder123")
End Sub
Public Function DirectoryFinder(PartialFolderName As String) As String
Dim FilePath As String
FilePath = Dir(CurrentProject.Path & "\DataFolder\" & PartialFolderName & "*", vbDirectory)
If FilePath <> "" Then
DirectoryFinder = CurrentProject.Path & "\DataFolder\" & FilePath
End If
End Function
Assign the result of the Dir-function directly to the variable and check if it is empty or not:
Dim FilePath As String, BasePath as String
BasePath = CurrentProject.Path & "\DataFolder\"
FilePath = Dir(BasePath & PartialFolderName & "*", vbDirectory)
If FilePath <>"" Then
' FilePath now contains the name of the folder that was found.
' The full Path would be BasePath & FilePath
...
End If
Worth noting that vbDirectory will find both folders and files which match the supplied pattern, so you should consider making sure what you found was a folder and not a file. Also maybe allow for cases where >1 folders match your pattern.
Sub tester()
Dim folders As Collection
Set folders = MatchedDirectories("C:\Tester\", "tmp -*")
Debug.Print folders.Count
If folders.Count = 0 Then
'no matches
ElseIf folders.Count = 1 Then
'one match
Else
'multiple matches
End If
End Sub
Public Function MatchedDirectories(searchIn As String, PartialFolderName As String) As Collection
Dim f As String, col As New Collection
If Right(searchIn, 1) <> "\" Then searchIn = searchIn & "\"
f = Dir(searchIn & PartialFolderName, vbDirectory)
Do While Len(f) > 0
'make sure it's a directory we found...
If GetAttr(searchIn & f) = vbDirectory Then col.Add searchIn & f
f = Dir()
Loop
Set MatchedDirectories = col
End Function

How to convert all *.potx files to *.pptx files with VBA?

I have a folder of ~20 *.potx files and I would like to convert all *.potx files to *.pptx, then delete the *.potx files.
The following will loop through all your templates, convert, and delete the template files.
Sub loopFiles()
Dim fso As New FileSystemObject
Dim fil As File
Dim fold As Folder
Set fold = fso.GetFolder(yourFolder)
For Each fil In fold.Files
If InStr(1, fil.Name, ".potx") > 0 Then
Application.Presentations.Open fil.Path
ActivePresentation.SaveAs Replace(fil.Path, ".potx", ".pptx"), ppSaveAsDefault
ActivePresentation.Close
'if you truly want to delete them, don't recommend since they are .potx
fil.Delete True
End If
Next fil
End Sub
You could try something like this: (replace YOUR FOLDER HERE with your folder name)
Public Sub ConvertPP()
Dim pApp As Object
Set pApp = CreateObject("Powerpoint.Application")
Dim sFile As String
Dim sFolder As String
sFolder = "YOUR FOLDER HERE"
sFile = Dir(sFolder & "\*.potx")
Do Until sFolder = ""
pApp.Presentations.Open sFolder & "\" & sFile
pApp.ActivePresentation.SaveAs sFolder & "\" & Replace(sFile, "potx", "pptx"), 11
pApp.ActivePresentation.Close
sFile = Dir()
Loop
pApp.Quit
Set pApp = Nothing
End Sub

VBA; how to extract all files names from a folder - without using Application.FileDialog object

As in the Question: the task is to extract all files names from a folder, but the folder path needs to be hard coded into the macro, to prevent these dialog boxes asking me things and wasting my time.
I will not change this folder. It will be the same one until the end of time, and I want to extract the files names into the Excel column, starting from second row.
this is the folder I want to extract ALL files names from.
"C:\Users\michal\SkyDrive\csv\bossa\mstcgl_mst\"
this is my portion of code:
Option Explicit
Sub GetFileNames()
Dim axRow As Long ' inside the Sheet("Lista") row#
Dim xDirectory As String
Dim xFname As String ' name of the file
Dim InitialFoldr$
Dim start As Double
Dim finish As Double
Dim total_time As Double
start = Timer
ThisWorkbook.Sheets("Lista").Range("D2").Activate
InitialFolder = "C:\Users\michal\SkyDrive\csv\bossa\mstcgl_mst"
If Right(InitialFolder, 1) <> "\" Then
InitialFolder = InitialFolder & "\"
End If
Application.InitialFolder.Show
If InitialFolder.SelectedItems.Count <> 0 Then
xDirectory = .SelectedItems(1) & "\"
xFname = Dir(xDirectory, vbArchive)
' Dir's job is to return a string representing
' the name of a file, directory, or an archive that matches a specified pattern.
Do While xFname <> "" ' there is already xFname value (1st file name) assigned.
ActiveCell.Offset(xRow) = xFname
xRow = xRow + 1 ' następny xRow
xFname = Dir()
Loop
End If
End With
finish = Timer ' Set end time.
total_time = Round(finish - start, 3) ' Calculate total time.
MsgBox "This code ran successfully in " & total_time & " seconds", vbInformation
End Sub
this is the line that crushes:
If InitialFolder.SelectedItems.Count <> 0 Then
xDirectory = .SelectedItems(1) & "\"
And two more important questions in the .png file.
Please, respond to them as well - it's very important 4 me.
Or if U guys know any other method to do this faster just don't hesitate and share Your Code with me - I'll be very grateful.
Sub Files()
Dim sht As Worksheet
Dim strDirectory As String, strFile As String
Dim i As Integer: i = 1
Set sht = Worksheets("Sheet1")
strDirectory = "C:\Users\User\Desktop\"
strFile = Dir(strDirectory, vbNormal)
Do While strFile <> ""
With sht
.Cells(i, 1) = strFile
.Cells(i, 2) = strDirectory + strFile
End With
'returns the next file or directory in the path
strFile = Dir()
i = i + 1
Loop
End Sub
See example below
Public Sub Listpng()
Const strFolder As String = "C:\SomeFolder\"
Const strPattern As String = "*.png"
Dim strFile As String
strFile = Dir(strFolder & strPattern, vbNormal)
Do While Len(strFile) > 0
Debug.Print strFile '<- view this in Immediate window; Ctrl+g will take you there
strFile = Dir
Loop
End Sub
There's a couple of procedures I use depending on whether I want subfolders as well.
This loops through the folder and adds path & name to a collection:
Sub Test1()
Dim colFiles As Collection
Dim itm As Variant
Set colFiles = New Collection
EnumerateFiles "C:\Users\michal\SkyDrive\csv\bossa\mstcgl_mst\", "*.xls*", colFiles
For Each itm In colFiles
Debug.Print itm
Next itm
End Sub
Sub EnumerateFiles(ByVal sDirectory As String, _
ByVal sFileSpec As String, _
ByRef cCollection As Collection)
Dim sTemp As String
sTemp = Dir$(sDirectory & sFileSpec)
Do While Len(sTemp) > 0
cCollection.Add sDirectory & sTemp
sTemp = Dir$
Loop
End Sub
This second way goes through the subfolders as well returning path & name. For some reason if you change InclSubFolders to False it only returns the name - got to sort that bit out.
Sub Test2()
Dim vFiles As Variant
Dim itm As Variant
vFiles = EnumerateFiles_2("C:\Users\michal\SkyDrive\csv\bossa\mstcgl_mst\", "xls*")
For Each itm In vFiles
Debug.Print itm
Next itm
End Sub
Public Function EnumerateFiles_2(sDirectory As String, _
Optional sFileSpec As String = "*", _
Optional InclSubFolders As Boolean = True) As Variant
EnumerateFiles_2 = Filter(Split(CreateObject("WScript.Shell").Exec _
("CMD /C DIR """ & sDirectory & "*." & sFileSpec & """ " & _
IIf(InclSubFolders, "/S ", "") & "/B /A:-D").StdOut.ReadAll, vbCrLf), ".")
End Function

Create a vba code to replace all the headers, of all the word documents in a Folder and Subfolders

Sub ReplaceEntireHdr()
Dim wrd As Word.Application
Set wrd = CreateObject("word.application")
wrd.Visible = True
AppActivate wrd.Name
'Change the directory to YOUR folder's path
fName = Dir("C:\Users\user1\Desktop\A\*.doc")
Do While (fName <> "")
With wrd
'Change the directory to YOUR folder's path
.Documents.Open ("C:\Users\user1\Desktop\A\" & fName)
If .ActiveWindow.View.SplitSpecial = wdPaneNone Then
.ActiveWindow.ActivePane.View.Type = wdPrintView
Else
.ActiveWindow.View.Type = wdPrintView
End If
.ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
.Selection.WholeStory
.Selection.Paste
.ActiveDocument.Save
.ActiveDocument.Close
End With
fName = Dir
Loop
Set wrd = Nothing
End Sub
I use this vba code to replace all the headers, of all the word documents in a folder 'A'. However if there is any subfolder in the parent folder 'A' with word documents, the vba code skips those documents. Could anyone please tell me how to include the word documents in the subfolders as well? Perhaps by making some changes in the code or any other vba code which can do the same job.
Thanks in advance.
In order to pick up the folders (directories) you need to specify the vbDirectory attribute. By default, Dir only "sees" things that match vbNormal.
Here's an example that picks up both files and sub-directories. The GetAttr function checks whether the file attribute is vbDirectory. If it's not, then it's a file.
What you can do is save the directory paths in an array, then loop that to get the files in the sub-directories.
Sub GetFilesandSubDir()
Dim sPath As String, sPattern As String
Dim sSearch As String, sFile As String
Dim sPathSub As String, sSearchSub As String
Dim aSubDirs As Variant, i As Long
sPattern = "*.*"
sPath = "C:\Test\"
sSearch = sPath & sPattern
sFile = Dir(sPath, vbNormal + vbDirectory)
aSubDirs = TestDirWithSubFolders(sPath, sPattern, sSearch, sFile)
For i = LBound(aSubDirs) To UBound(aSubDirs)
Debug.Print "Directory: " & aSubDirs(i)
sPathSub = sPath & aSubDirs(i) & "\"
sSearchSub = sPathSub & sPattern
sFile = Dir(sPathSub, vbNormal + vbDirectory)
TestDirWithSubFolders sPathSub, sPattern, sSearchSub, sFile
Next
End Sub
Function TestDirWithSubFolders(sPath As String, sPattern As String, _
sSearch As String, sFile As String) As Variant
Dim aSubDirs() As Variant, i As Long
i = 0
Do While sFile <> ""
If GetAttr(sPath & sFile) = vbDirectory Then
'Debug.Print "Directory: " & sFile
ReDim Preserve aSubDirs(i)
aSubDirs(i) = sFile
i = i + 1
Else
Debug.Print "File: " & sFile
End If
sFile = Dir
Loop
TestDirWithSubFolders = aSubDirs
End Function