DIR does not recognize wildcard "*" - vba

The following code does not find the file:
xTempTmtl = "Z:\20.0 Global storage\20.1 Design Packages*" & xNewName
where xNewName = "SLR-D&C-MI0-000-TRS-007199.Pdf"
but
xTempFol = Dir("Z:\20.0 Global storage\20.1 Design Packages\DP01.1 Stops - Zone C (North)\02. Transmittals\" & xNewName)
finds the file.
Problem is that the file xNewName could be in any one of 80 folders(Dp01.1..., DP01.2....) etc, then in \02. Transmittals\
If I put a \ after the *, I get Bad file name error.
Why is the wildcard "*" not recognized?
This happens on two separate machines, one running EXCEL2010 on a Windows& PC and the other running EXCEL365 on a Windows10 laptop.

Wildcards are used to return all file or folder names in a directory. Using the Dir() function with parameters changes the path in which the function will search for files. Subsequent calls to the Dir() function will return the next file or folder after the previous call. The Dir() will not search subdirectories for a file.
You will need to do a recursive set the Dir() Attributes parameter to vbDirectory to return the subfolder names then search each subfolder.
You can find plenty of examples that use the FileSystemObject to recursively search subfolder for a file. I thought that it would be interesting to write one that uses the Dir() function.
Function FindFile(ByVal folderName As String, ByVal FileName As String, Optional ByRef FoundFile As String) As String
Dim search As String
Dim dirList As New Collection
If Not Right(folderName, 1) = "\" Then folderName = folderName & "\"
search = Dir(folderName & "\*", vbDirectory)
While Len(search) > 0
If Not search = "." And Not search = ".." Then
If GetAttr(folderName & search) = 16 Then
dirList.Add folderName & search
Else
If LCase(search) = LCase(FileName) Then
FoundFile = folderName & FileName
FindFile = FoundFile
Exit Function
End If
End If
End If
search = Dir()
Wend
Dim fld
For Each fld In dirList
If Len(FoundFile) > 0 Then
FindFile = FoundFile
Exit Function
Else
FindFile = FindFile(CStr(fld), FileName, FoundFile)
End If
Next
End Function

Related

Saving outlook emails in folders and subfolder to local drive and preserve original directory error

I used below code to save outlook emails in folders and subfolder to local drive and preserve original directory.
Private objFileSystem As Object
Private Sub ExportFolderWithAllItems()
Dim objFolder As Outlook.Folder
Dim strPath As String
'Specify the local folder where to save the emails
strPath = "C:\Users\qiaoqiao\"
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
'Select a Outlook PST file or Outlook folder
Set objFolder = Outlook.Application.Session.PickFolder
Call ProcessFolders(objFolder, strPath)
MsgBox "Email saving is completed", vbExclamation
End Sub
Private Sub ProcessFolders(objCurrentFolder As Outlook.Folder, strCurrentPath As String)
Dim objItem As Object
Dim strSubject, strFileName, strFilePath As String
Dim objSubfolder As Outlook.Folder
'Create local folder based on Outlook mailbox folder directory
strCurrentPath = strCurrentPath & ModifyName(objCurrentFolder.Name)
objFileSystem.CreateFolder strCurrentPath
For Each objItem In objCurrentFolder.Items
strSubject = ModifyName(objItem.Subject)
strFileName = strSubject & ".msg"
strFilePath = strCurrentPath & "\" & strFileName
i = 0
Do Until False
strFilePath = strCurrentPath & "\" & strFileName
'Check if there exist emails with the same subject
If objFileSystem.FileExists(strFilePath) Then
'Add order number to the end of the subject
i = i + 1
strFileName = strSubject & " (" & i & ").msg"
Else
Exit Do
End If
Loop
'Save as MSG file
'On Error Resume Next
'Debug.Print Len(strFilePath)
objItem.SaveAs strFilePath, olMSG
Next
'Process subfolders recursively
If objCurrentFolder.Folders.Count > 0 Then
For Each objSubfolder In objCurrentFolder.Folders
Call ProcessFolders(objSubfolder, strCurrentPath & "\")
Next
End If
End Sub
Function ModifyName(folderName As String) As String
'Dim folderName As String
'In order to save emails in the same directory as in Outlook,
'when creating the folders in local drive,
'the folder name must not contain some special characters
folderName = Replace(folderName, ":", "")
folderName = Replace(folderName, "|", "")
folderName = Replace(folderName, ",", "")
folderName = Replace(folderName, "'", "")
folderName = Replace(folderName, "(", "")
folderName = Replace(folderName, ")", "")
folderName = Replace(folderName, "~", "")
folderName = Replace(folderName, "*", "")
folderName = Replace(folderName, "?", "")
folderName = Replace(folderName, "/", "")
folderName = Replace(folderName, "\", "")
folderName = Replace(folderName, """", "")
folderName = Trim(folderName)
'folderName = Replace(folderName, Chr(34), "")
ModifyName = folderName
End Function
However, since there are many layers of folders, so the strFilePath become very long, and it gave me a runtime error saying Operation failed.
Can anyone please advise me how to solve this issue? thank you in advance!!!
In Office products there is a limit to the number of characters in the file path. This error message occurs when you save or open a file if the path to the file (including the file name) exceeds 218 characters. This limitation includes three characters representing the drive, the characters in folder names, the backslash character between folders, and the characters in the file name.
Make sure that the path to the file contains fewer than 219 characters. To do this, use one of the following methods:
Rename the file so that it has a shorter name.
Rename one or more folders that contain the file so that they have shorter names.
Move the file to a folder with a shorter path name.
Note that if you enter 255 characters in the File Name box in the
Save As dialog box, and click OK, you will receive the following error message:
The path you entered, "<path>", is too long. Enter a shorter path.
Also, if you attempt to save a file and the path exceeds 255 characters, you will receive the following error message:
The file could not be accessed. Try one of the following:
- Make sure the specified folder exists.
- Make sure the folder that contains the file is not read-only.
- Make sure the file name does not contain any of the following characters: < > ? [ ] : | *.
- Make sure the file/path name doesn't contain more than 218 characters.

programmatically (VBA) see if I have access to a folder

I am trying to read through folders on a drive to see which folders I have at least read access to. I have used the DIR function in MS Access VBA. Is there a more accurate way to determine if I have access. Below is how I am using DIR. Thanks
dim path as string
dim HaveAccess as integer
path = "C:\temp\"
If Dir(path) = "" Then
HaveAccess = 1 'no access
Else
HaveAccess = 2 'i have access
End if
You could use FileSystemObject, but you could also use the intrinsic GetAttr method:
Option Explicit
Private Sub Command1_Click()
Const path As String = "c:\"
Dim folder As String
Dim att As Variant
folder = Dir(path, vbDirectory)
Do While folder <> ""
If folder <> "." And folder <> ".." And (GetAttr(path & folder) And vbDirectory) = vbDirectory Then
att = GetAttr(path & folder) And vbReadOnly
If att = vbReadOnly Then Debug.Print folder & " - read only"
End If
folder = 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

Looping through all files in directory VBA

I'm trying to loop through all files in a given directory using VBA and replace a few words in each file before saving it in another directory. The method I'm using is:
With Application
Do While Len(fileName) > 0
Where fileName is:
fileName = Dir$("C:\FOLDER\" & "*")
After I run the code I have:
fileName = Dir
Loop
However, after it goes back to the top of the loop, it does not pick up any more files. I am sure there are multiple files in the given directory.. Any ideas?
Test it in separate Subs, this two codes works.
Sub LoopAllFiles()
Dim StrFile As String
StrFile = Dir$("C:\FOLDER\" & "*")
Do While Len(StrFile) > 0
StrFile = Dir
Loop
End Sub
Sub LoopAllFiles()
Dim StrFile As String
StrFile = Dir("C:\FOLDER\" & "*")
Do While StrFile <> ""
StrFile = Dir
Loop
End Sub

Crawling through Zip files

I'm trying to crawl through a certain drive and grab data off of certain .xls files that are buried in sub-directories. The drive is over a TB, and the folders don't all have the same hierarchy, so I'm crawling through all of them. So far, the script works great.
The problem is, there are zipped files in the drive. At least half the files are in zipped format. How can I crawl through these files as well?
Here is the part of my code that crawls through the sub-directories. There is another function "TrailingSlash" which just appends a "\" to the string if it doesn't already have one. I give credit to the author in my comments.
Public Function recursiveDir(colFiles As Collection, strFolder As String, strFileSpec As String, bIncludeSubfolders As Boolean) as Collection
'From Ammara.com/access_image_faq/recursive_folder_search.html
'Recursive function to search document tree from specific file extension
Dim strTemp As String
Dim colFolders As New Collection
Dim vFolderName As Variant
Dim colFiles As New Collection
Dim counter As Integer
'Add files in strFolder matching strFileSpec to colFiles
strFolder = TrailingSlash(strFolder)
strTemp = Dir(strFolder & strFileSpec)
On Error Resume Next
Do While strTemp <> vbNullString
colFiles.Add (strFolder & strTemp)
counter = counter + 1
Debug.Print ("files found: " & counter)
strTemp = Dir
Loop
If bIncludeSubfolders Then
'Fill colFolders with list of subdirectories of strFolder
strTemp = Dir(strFolder, vbDirectory)
Do While strTemp <> vbNullString
If (strTemp <> ".") And (strTemp <> "..") Then
If (GetAttr(strFolder & strTemp) And vbDirectory) <> 0 Then
colFolders.Add strTemp
End If
End If
strTemp = Dir
Loop
'Call recursiveDir for each subfolder in colFolders
For Each vFolderName In colFolders
Call recursiveDir(colFiles, strFolder & vFolderName, strFileSpec, True)
Next vFolderName
End If
recursiveDir = colFiles
End Function
The function adds all the path strings to the collection "colFolders", which I then use to open and extract data from. I'm now thinking there may not be a simple way to return a string path to a file within a zipped folder. There may need to be a separate function that is called when this function encounters a zip, that in turn crawls through the zipped folder and extracts the specific file to a local destination (as long as I don't have to extract the whole folder, we should be good).
I'm kind of lost in what I should do. Googleing around points me towards using shell.Application. I know nothing of shells, is this the path I should take?
Thanks SO - you all are awesome!
Try this code instead to search through subfolders:
Sub SO()
Dim x, i
x = GetFiles("C:\Users\SO\Folder", "*.xls*", True) '// x becomes an array of files found
For Each i In x
Debug.Print i
Next i
End Sub
'-------------------------------------------------
Function GetFiles(StartPath As String, FileType As String, SubFolders As Boolean) As Variant
StartPath = StartPath & IIf(Right(StartPath, 1) = "\", vbNullString, "\") 'Sanity check
GetFiles = Split(Join(Filter(Split(CreateObject("WScript.Shell").Exec("CMD /C DIR """ & StartPath & FileType & """ " & _
IIf(SubFolders, "/S", vbNullString) & " /B /A:-D").StdOut.ReadAll, vbCrLf), ":"), "#"), "#")
End Function
But for zip files, there isn't really anything native to windows that will allow you to do this other than the CreateObject("Shell.Application").Namespace(zipName).Items method.
I prefer to use 7-zip which is free, open-source and has a great command line utility which means you can access it via VBA too using the CreateObject("WScript.Shell") method (like above)