Dir() function understanding - vba

' Display the names in C:\ that represent directories.
MyPath = "c:\" ' Set the path.
MyName = Dir(MyPath, vbDirectory) ' Retrieve the first entry.
Do While MyName <> "" ' Start the loop.
' Use bitwise comparison to make sure MyName is a directory.
If (GetAttr(MyPath & MyName) And vbDirectory) = vbDirectory Then
' Display entry only if it's a directory.
MsgBox(MyName)
End If
MyName = Dir() ' Get next entry.
Loop
I am looking at the above code. I specifically don't understand what the "MyName = Dir()" does. It is commented it gets the next entry, but I don't understand how it gets the next entry - specifically what is Dir() doing?

Dir is function which has a edge effect.
the first call to Dir: MyName = Dir(MyPath, vbDirectory) initializes the Dir internals and returns the first directory entry.
Subsequent calls to Dir use the same context, yielding MyPath directory contents one by one.
It's not reentrant (which is also why you can't nest/recurse multiple loops using Dir), not very elegant, but that's how it works.

According to the Dir() MSDN, it
Returns a string representing the name of a file, directory, or folder that matches a specified pattern or file attribute, or the volume label of a drive.

Related

VBA unable to move on to next file in Directory, instead picking file named ".."

I am having a little issue with the Loop function to open files within a Directory. Find the code below:
'Build the complete folder path:
strTargetFolder_Batch = "I:\PerfTeam"
strTargetFolder_Batch = strTargetFolder_Batch & strMonthNo & " " & strMonthName & " " & strYear & "\" & "Attribution - Draft"
If Right(strTargetFolder_Batch, 1) <> "\" Then
strTargetFolder_Batch = strTargetFolder_Batch & "\"
End If
If Not CreateFolder(strTargetFolder_Batch) Then
MsgBox "Unable to create the folder:" & vbCrLf & strTargetFolder_Batch, vbExclamation
Else
End If
FolderPath = strTargetFolder_Batch
'Sets Parameters to Open the file
MyFolder = FolderPath 'location of files
MyExtension = "*.xlsx*"
MyFile = Dir(MyFolder & MyExtension)
Do While MyFile <> "" 'will start LOOP until all files in MyFolder have been looped through
Set oWbk = Workbooks.Open(MyFolder & "\" & MyFile)
*Batch Run is a Boolean function*
'*** 1. Calls Import Data Macro, which Imports the Data ***'
Call Import_new_data(Batch_Run, oWbk)
'*** 2. Calls Data Collector Macro, which Analyses the Data ***'
Call Data_Collector(Batch_Run)
'*** 3. Calls Report Production Macro, which Produces Report ***'
Call Report_Production_Sub(Batch_Run)
ContinueLoop:
MyFile = Dir
'**^^ Here is where the Macro breaks after completing a full first iteration** !
Loop
What essentially the macro does, it picks up data from the opened file, closes the file and then analyses it, before creating a report out of it. It should then move on the second file in the folder and perform the same operation.
While the first file gets opened fine, and analysed as it should, the problem arises moving on to the second file. The variable MyFile in fact picks up a 'Ghost' file named ".." which then throws an error of course as it does not exist. Doing some research I have found out this may relate to the Directory path.
Any help would be super appreciated!
Calling the Dir function with parameter starts a search for matching files. If nothing is specified as second parameter, is will search only regular files (no directories, no hidden files etc).
Any following calls to Dir (without parameter) will continue the last search initiated by a Dir(with parameter).
The .. you get as result of the Dir within your loop is not a file, it's a folder (up directory). You will get this only when you started a Dir with option vbDirectory as second parameter. As this parameter is missing in your code, I would strongly assume that anywhere in your code (that is not displayed) a new Dir-search is started (which destroys the search results of a previous Dir-search).
Update: If you need to check if a folder exists but don't want to destroy your Dir-Loop, you could use the FileSystemObject. The FileSystemObject is usefull for several things concerning files and folders.
if CreateObject("Scripting.FileSystemObject").FolderExists("<enter your path>") then

Print File - Macro

I have created a macro that I can use to print PDF files. The PDF files will be saved in a folder to print. The path will be given that folder path where I save all PDF files. My questions are:
1) Once the files are saved in folder, is it possible to sort it automatically like first come first print. Now the issue is - prints did not come out in order of how the files are – we have to reconcile all files, so looking for each one in a random list order would take lots of time.
2) Is it possible to have the files automatically deleted from the folder after the printing is completed?
Public Sub Print_All_PDF_Files_in_Folder()
Dim folder As String
Dim PDFfilename As String
folder = "\\maple.fg.rbc.com\data\toronto\user_3\315606053\myWorkspace\Desktop\test" 'CHANGE AS REQUIRED
If Right(folder, 1) <> "\" Then folder = folder & "\"
PDFfilename = Dir(folder & "*.pdf", vbNormal)
While Len(PDFfilename) <> 0
If Not PDFfilename Like "*ecg*" Then
Print_PDF folder & PDFfilename
End If
PDFfilename = Dir() ' Get next matching file
Wend
End Sub
Sub Print_PDF(sPDFfile As String)
Shell "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe /p /h " & Chr(34) & sPDFfile & Chr(34), vbNormalFocus
' This is path of Adobe in the desktop
End Sub
There is no build in way to sort files. However, it is rather easy to read the filenames and -dates into arrays and sort them manually, but you have to use the FilesystemObject rather than using dir to get the file dates.
You can find an example to do so for example here: https://social.msdn.microsoft.com/Forums/office/en-US/5f27936e-1d98-44df-8f69-0f81624c4b92/read-files-in-a-folder-in-descending-order-with-file-name-or-date-created?forum=accessdev
The command to delete a file with VBA is kill, or you can use the .DeleteFile method of FilesystemObject. However, this will work only if the printing is already done, so you have to wait for your shell-command to finish. For this, you have to use the wscript.shell, see for example here https://stackoverflow.com/a/8906912/7599798

strDirName = Dir(strParentFolder, vbDirectory)

This code:
strDirName = Dir(strParentFolder, vbDirectory)
Do Until strDirName = ""
returns files as well folders. It should only return folders.
Is it possible to use Dir to return a list of subfolders? Or is it recommended to use FileSystemObject(s)?
From the documentation page "files with no attributes" will also be returned so you may wish to check those.
Dir Function
Applies To: Access 2016
https://support.office.com/en-gb/article/Dir-Function-1a1a4275-f92f-4ae4-8b87-41e4513bba2e
vbDirectory 16 Specifies directories or folders in addition to files with no attributes.
I can't make any recommendations on how to do what you're asking using Dir() but below is a generic example of how you'd accomplish that using FileSystemObject.
This will print a single string of the first level of sub-directories in relation to the root directory.
Sub GetFolderList()
Set fso = CreateObject("Scripting.FileSystemObject")
Set rootFolder = fso.GetFolder("*Root Directory URI*")
Set subFolders = rootFolder.subFolders
Folders = ""
For Each fld In subFolders
Folders = Folders & fld.Name
Folders = Folders & " "
Next
Debug.Print Folders
End Sub

VBA "Check if folder exists" works only when there is a file in the folder

I got the original code from www.rondebruin.nl
It is designed to test whether or not a folder already exists in the directory. I modified it to fit my needs and it seemed to work well.
Today, i discovered that it only works properly if the folder being tested for is NOT empty. If it is empty, then it returns false (i.e. the folder does not exist).
I can't figure out why this is.
FolderPath = sPfad
If Right(FolderPath, 1) <> "\" Then
FolderPath = FolderPath & "\"
End If
TestStr = ""
On Error Resume Next
TestStr = Dir(FolderPath)
On Error GoTo 0
If TestStr = "" Then
Test_Folder_Exist_With_Dir = False
Exit Function
Else
Test_Folder_Exist_With_Dir = True
Exit Function
End If
I suspect the answer lies in the TestStr = Dir(FolderPath) but haven't been able to get to the bottom of it. The MSDN article basically explains that Dir() always returns something. However the examples give are all such that there is a file present to return.
I basically need to get it so that it recognizes the folder regardless of whether there is something in it or not.
Any help appreciated!
The following line returns a number greater than 0 if the folder exists, regardless of whether the folder has any files in it
len(dir("C:\Users\user\Desktop\Tests\tt", vbDirectory))
You could try this instead:
Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FolderExists(FolderPath)
...

Why can't I delete this folder (VBA)?

I created a temporary folder that gets deleted later on in the program using this code:
'Creates a new temporary directory path for a folder copy
If dir("C:\\InventorTempFolder\\\", vbDirectory) = "" Then
MkDir "C:\\InventorTempFolder\\\"
SetAttr "C:\InventorTempFolder", vbNormal
Else: MsgBox "This folder already exists."
End If
(I don't know if the SetAttr is right...that's part of my question!)
I then pulled this code offline that should delete all the files and directories in this folder, using this code:
Sub DeleteDirectory()
Dim dir_name As String
Dim file_name As String
Dim files As Collection
Dim i As Integer
dir_name = "C:\\InventorTempFolder"
' Get a list of files it contains.
Set files = New Collection
file_name = dir$(dir_name & "\*.*", vbReadOnly + _
vbHidden + vbSystem + vbDirectory)
Do While Len(file_name) > 0
If (file_name <> "..") And (file_name <> ".") Then
files.Add dir_name & "\" & file_name
End If
file_name = dir$()
Loop
' Delete the files.
For i = 1 To files.Count
file_name = files(i)
' See if it is a directory.
If GetAttr(file_name) = vbDirectory Then
Kill file_name
Else: Kill file_name
End If
Next i
' The directory is now empty. Delete it.
RmDir dir_name
' Remove the read-only flag if set.
' (Thanks to Ralf Wolter.)
End Sub
However, the directory won't delete. My theory is that it is because the directory is a read-only folder. That is why I tried to change the attribute to vbNormal, but it won't change. So questions I'm wondering is:
Why won't it delete? Is my theory right that it is because it is read-only?
If so, how can I fix that?
If not, what else is wrong...?
Thanks ahead of time!
The end of your script is:
RmDir dir_name
' Remove the read-only flag if set.
' (Thanks to Ralf Wolter.)
RmDir dir_name
So you're attempting to remove the same directory twice. And dir_name at this point is set to the "SillyVBA" directory -- this did get deleted when I tested it. I'm assuming the second RmDir is meant to delete "C:\InventorTempFolder"; that also worked for me when I tested it.
Updated in response to comment
The problem is likely due to your attempt to use Kill when the file type is a directory. To do a full recursive delete, you would need to start at the bottom of the tree, deleting all files and empty directories as you work your way up. However a much easier way is to use FileSystemObject:
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
fso.deletefolder dir_name
This will delete the directory and everything in it, in one shot.