I have a sub that calls a function that searches through subfolders and then returns a file path with file name so that the main sub can then use that string to create an attachment. It is a recursive function and as such it keeps resetting my value in strJDFile. I need it to search through all the subfolders as it does, find my file, and then send the strJDFile value through to the main sub. Since it keeps resetting, nothing makes it through to the sub. What am I doing wrong? The function works otherwise. It is just the last step of getting the result to carry through.
Function recurse(sPath As String)
Dim FSO As New FileSystemObject
Dim myFolder As Scripting.Folder
Dim mySubFolder As Scripting.Folder
Dim myFile As Scripting.File
Dim strName As String
Dim strJDFile As String
Dim strDir As String
Dim strJDName As String
Set myFolder = FSO.GetFolder(sPath)
strName = Range("a2").Offset(0, 3)
For Each mySubFolder In myFolder.SubFolders
For Each myFile In mySubFolder.Files
If myFile.name Like "*" & strName & "*" Then
strJDName = myFile.name
strDir = mySubFolder & "\"
strJDFile = strDir & strJDName
Exit Function
End If
Next
recurse = recurse(mySubFolder.Path)
Next
End Function
I looked at multiple posts on this issue including this one VBA macro that search for file in multiple subfolders and I upvoted the answer there, but that is how to set up a recursive, not how to make the value come through to the sub. The issue is as I said above, each time it hits the 'Next' it resets, so my strJDFile value gets set to "" again. But you need the Next after the recurse-strDir in order to get it to keep going through to the next subfolder until if finds the right value. I just need the value to remain instead of coming through as blank. I stepped through with F8 and that is how I found that it resets when it hits the final Next. That is why I added the Exit Function, but that did not work either.
"recurse" is returned, not strJDFile.
Private Sub functionTest()
Dim x As String
Dim fPath As String
fPath = "C:\Test"
x = recurse(fPath)
If x = "" Then x = "No results."
Debug.Print " *** recurse has returned: " & x
Debug.Print "Done"
End Sub
Function recurse(sPath As String)
Dim FSO As New FileSystemObject
Dim myFolder As Scripting.folder
Dim mySubFolder As Scripting.folder
Dim myFile As Scripting.file
Dim strName As String
Dim strJDFile As String
Dim strDir As String
Dim strJDName As String
Set myFolder = FSO.GetFolder(sPath)
' strName = Range("a2").Offset(0, 3)
strName = "test.xlsx"
For Each mySubFolder In myFolder.SubFolders
Debug.Print " mySubFolder: " & mySubFolder
For Each myFile In mySubFolder.Files
If myFile.name Like "*" & strName & "*" Then
strJDName = myFile.name
strDir = mySubFolder & "\"
strJDFile = strDir & strJDName
recurse = strJDFile
Exit Function
Else
Debug.Print " myFile.name: " & myFile.name
End If
Next
recurse = recurse(mySubFolder.path)
Next
End Function
Related
I'm trying to upload files to SharePoint using VBA within Excel.
I found some urlmon code which has solved the file download.
I've seen code which focuses on Scripting.FileSystemObject using UNC, winhttp POST and SEND and the SP SDK but I've not been able to make the latter work due to site and software install limitations.
I need to directly upload, for e.g. to "http://example.com/foldername". I tried using Scripting.FileSystemObject with the URL.
I'm making a bold assumption that there is a VBA method other than UNC and winhttp POST/SEND for uploading files to SharePoint.
Code I've tried, copied from someone else's work on Stack Overflow.
Public Function UploadEICRs(ByVal file As String, uploadFolder As String)
Dim SharepointAddress As String
Dim LocalAddress As String
Dim objNet As Object
Dim FS As Object
' Where you will enter Sharepoint location path
SharepointAddress = "https://example.com/test_folder/"
' Where you will enter the file path, ex: Excel file
LocalAddress = file
SPFolder = SharepointAddress & uploadFolder & "/"
Debug.Print SPFolder
Set objNet = CreateObject("WScript.Network")
Set FS = CreateObject("Scripting.FileSystemObject")
If FS.FileExists(LocalAddress) Then
FS.CopyFile LocalAddress, SPFolder
End If
Set objNet = Nothing
Set FS = Nothing
End Function
Sub uploadFiles()
Dim FileSystem As Object
Dim HostFolder As String
HostFolder = GetFolder
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(HostFolder)
End Sub
Sub DoFolder(folder)
Dim SubFolder
Dim LString As String
Dim LArray() As String
Dim CertFolder As String
Dim ufile As String
Dim pFolder As String
LString = folder
LArray = Split(LString, "\")
For Each SubFolder In folder.SubFolders
DoFolder SubFolder
Next
Dim file
For Each file In folder.Files
CertFolder = LArray(3)
pFolder = LArray(0) & "\" & LArray(1) & "\" & LArray(2)
Debug.Print CertFolder
Debug.Print file
Debug.Print pFolder
ufile = file
sendfile2 ufile, CertFolder, pFolder
Next
End Sub
Public Sub sendfile2(ByVal file As String, sUrl As String, fPath As String)
On Error GoTo err_Copy
Dim xmlhttp As MSXML2.XMLHTTP60
Dim sharepointUrl
Dim sharepointFileName
Dim tsIn
Dim sBody
Dim LlFileLength As Long
Dim Lvarbin() As Byte
Dim LobjXML As Object
Dim LstrFileName As String
Dim LvarBinData As Variant
Dim PstrFullfileName As String
Dim PstrTargetURL As String
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim fldr
Dim f
Dim pw As String
Dim UserName As String
Dim RetVal
Dim I As Integer
Dim totFiles As Integer
Dim Start As Date, Finish As Date
Debug.Print file
Debug.Print sUrl
sharepointUrl = "https://example.com/folder/folder"
Set LobjXML = CreateObject("Microsoft.XMLHTTP")
mypath = sharepointUrl & "/" & sUrl
Debug.Print mypath
LobjXML.Open "HEAD", mypath, False 'Check for Directory
LobjXML.Send
If LobjXML.StatusText = "NOT FOUND" Then
'Create directory if not there
LobjXML.Open "MKCOL", mypath, False
LobjXML.Send
End If
Set fldr = fso.GetFolder(fPath & "\" & sUrl)
Debug.Print fldr
totFiles = fldr.Files.Count
For Each f In fldr.Files
sharepointFileName = sharepointUrl & "/" & sUrl & "/" & f.Name
Debug.Print sharepointFileName
PstrFullfileName = fPath & "\" & sUrl & "\" & f.Name
LlFileLength = FileLen(PstrFullfileName) - 1
Debug.Print PstrFullfileName
' Read the file into a byte array.
If LlFileLength <> 0 Then
ReDim Lvarbin(LlFileLength)
Open PstrFullfileName For Binary As #1
Get #1, , Lvarbin
Close #1
End If
' Convert to variant to PUT.
LvarBinData = Lvarbin
PstrTargetURL = sharepointUrl & "/" & sUrl & "/" & f.Name
' Put the data to the server, false means synchronous.
LobjXML.Open "PUT", PstrTargetURL, False
' Send the file in.
LobjXML.Send LvarBinData
'End If
I = I + 1
'RetVal = SysCmd(acSysCmdSetStatus, "File " & I & " of " & totFiles & " copied...")
Next f
'RetVal = SysCmd(acSysCmdClearStatus)
Set LobjXML = Nothing
Set fso = Nothing
err_Copy:
If Err <> 0 Then
MsgBox Err & " " & Err.Description
End If
End Sub
Function GetFolder() As String
Dim fldr As FileDialog
Dim sItem As String
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select a Folder"
.AllowMultiSelect = False
.InitialFileName = Application.DefaultFilePath
If .Show <> -1 Then GoTo NextCode
sItem = .SelectedItems(1)
End With
NextCode:
GetFolder = sItem
Set fldr = Nothing
End Function
You have to use the SharePoint API, in order to securely log in and add files to a document library. If you can make HTTP calls from your VBA code, then you can use the SharePoint REST API, or you can download the SharePoint 2013 Client Components SDK, and then reference the Client-Side Object Model (CSOM) .dlls from VBA. Beware that most of Microsoft's examples are in C#, but are adaptable to VB.
I have macro, if I put in cell E1 name of the file, macro search trough C:\Users\Marek\Desktop\Makro\ directory, find it and put the needed values in specific cells of my original file with macro.
Is it possible to make this work without specific folder location? I need something that can search trough C:\Users\Marek\Desktop\Makro\ with many subfolders in it.
My code:
Sub Zila1()
Dim SaveDriveDir As String, MyPath As String
Dim FName As Variant
Dim YrMth As String
SaveDriveDir = CurDir
MyPath = Application.DefaultFilePath 'or use "C:\Data"
ChDrive MyPath
ChDir MyPath
FName = Sheets("Sheet1").Range("E1").Text
If FName = False Then
'do nothing
Else
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"A16:A17", Sheets("Sheet1").Range("B2:B3"), True, False
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"AE23:AE24", Sheets("Sheet1").Range("B3:B4"), True, False
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"AE26:AE27", Sheets("Sheet1").Range("B4:B5"), True, False
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"AQ59:AQ60", Sheets("Sheet1").Range("B5:B6"), True, False
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"AR65:AR66", Sheets("Sheet1").Range("B6:B7"), True, False
End If
ChDrive SaveDriveDir
ChDir SaveDriveDir
End Sub
Just for fun, here's a sample with a recursive function which (I hope) should be a bit simpler to understand and to use with your code:
Function Recurse(sPath As String) As String
Dim FSO As New FileSystemObject
Dim myFolder As Folder
Dim mySubFolder As Folder
Set myFolder = FSO.GetFolder(sPath)
For Each mySubFolder In myFolder.SubFolders
Call TestSub(mySubFolder.Path)
Recurse = Recurse(mySubFolder.Path)
Next
End Function
Sub TestR()
Call Recurse("D:\Projets\")
End Sub
Sub TestSub(ByVal s As String)
Debug.Print s
End Sub
Edit: Here's how you can implement this code in your workbook to achieve your objective.
Sub TestSub(ByVal s As String)
Dim FSO As New FileSystemObject
Dim myFolder As Folder
Dim myFile As File
Set myFolder = FSO.GetFolder(s)
For Each myFile In myFolder.Files
If myFile.Name = Range("E1").Value Then
Debug.Print myFile.Name 'Or do whatever you want with the file
End If
Next
End Sub
Here, I just debug the name of the found file, the rest is up to you. ;)
Of course, some would say it's a bit clumsy to call twice the FileSystemObject so you could simply write your code like this (depends on wether you want to compartmentalize or not):
Function Recurse(sPath As String) As String
Dim FSO As New FileSystemObject
Dim myFolder As Folder
Dim mySubFolder As Folder
Dim myFile As File
Set myFolder = FSO.GetFolder(sPath)
For Each mySubFolder In myFolder.SubFolders
For Each myFile In mySubFolder.Files
If myFile.Name = Range("E1").Value Then
Debug.Print myFile.Name & " in " & myFile.Path 'Or do whatever you want with the file
Exit For
End If
Next
Recurse = Recurse(mySubFolder.Path)
Next
End Function
Sub TestR()
Call Recurse("D:\Projets\")
End Sub
This sub will populate a Collection with all files matching the filename or pattern you pass in.
Sub GetFiles(StartFolder As String, Pattern As String, _
DoSubfolders As Boolean, ByRef colFiles As Collection)
Dim f As String, sf As String, subF As New Collection, s
If Right(StartFolder, 1) <> "\" Then StartFolder = StartFolder & "\"
f = Dir(StartFolder & Pattern)
Do While Len(f) > 0
colFiles.Add StartFolder & f
f = Dir()
Loop
If DoSubfolders then
sf = Dir(StartFolder, vbDirectory)
Do While Len(sf) > 0
If sf <> "." And sf <> ".." Then
If (GetAttr(StartFolder & sf) And vbDirectory) <> 0 Then
subF.Add StartFolder & sf
End If
End If
sf = Dir()
Loop
For Each s In subF
GetFiles CStr(s), Pattern, True, colFiles
Next s
End If
End Sub
Usage:
Dim colFiles As New Collection
GetFiles "C:\Users\Marek\Desktop\Makro\", FName & ".xls", True, colFiles
If colFiles.Count > 0 Then
'work with found files
End If
If this helps, you can also use FileSystemObject to retrieve all subfolders of a folder.
You need to check the reference "Microsot Scripting Runtime" to get Intellisense and use the "new" keyword.
Sub GetSubFolders()
Dim fso As New FileSystemObject
Dim f As Folder, sf As Folder
Set f = fso.GetFolder("D:\Proj\")
For Each sf In f.SubFolders
'Code inside
Next
End Sub
I actually just found this today for something I'm working on. This will return file paths for all files in a folder and its subfolders.
Dim colFiles As New Collection
RecursiveDir colFiles, "C:\Users\Marek\Desktop\Makro\", "*.*", True
Dim vFile As Variant
For Each vFile In colFiles
'file operation here or store file name/path in a string array for use later in the script
filepath(n) = vFile
filename = fso.GetFileName(vFile) 'If you want the filename without full path
n=n+1
Next vFile
'These two functions are required
Public Function RecursiveDir(colFiles As Collection, strFolder As String, strFileSpec As String, bIncludeSubfolders As Boolean)
Dim strTemp As String
Dim colFolders As New Collection
Dim vFolderName As Variant
strFolder = TrailingSlash(strFolder)
strTemp = Dir(strFolder & strFileSpec)
Do While strTemp <> vbNullString
colFiles.Add strFolder & strTemp
strTemp = Dir
Loop
If bIncludeSubfolders Then
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
End Function
Public Function TrailingSlash(strFolder As String) As String
If Len(strFolder) > 0 Then
If Right(strFolder, 1) = "\" Then
TrailingSlash = strFolder
Else
TrailingSlash = strFolder & "\"
End If
End If
End Function
This is adapted from a post by Ammara Digital Image Solutions.(http://www.ammara.com/access_image_faq/recursive_folder_search.html).
I have a function that works to search through the subfolders of a given directory and finds the file name I need. However, it only goes through one set of subfolders, finding the first one and then going through to the end of the subfolders. However, it then just stops. I have looked through various threads and tried different options but no joy.
I need it to then loop back to the root directory (say, sPath=C:\Windows) and look at the next subfolder, go through that whole directory, come back to the root folder, and so on until it finds the file it needs. I cannot seem to get that part to work, hoping someone here can help point out what I am missing. I am trying to keep this set at a higher level root folder rather than have to start lower in in the directory to get it to work. Here is the function:
Function recurse(sPath As String, strname As String, strName3 As String)
Dim FSO As New FileSystemObject
Dim myFolder As Scripting.Folder
Dim mySubFolder As Scripting.Folder
Dim myFile As Scripting.file
Dim strJDFile As String
Dim strDir As String
Dim strJDName As String
Set myFolder = FSO.GetFolder(sPath)
' strName = Range("a2").Offset(0, 3)
strName3 = Replace(strName3, "/", " ")
For Each mySubFolder In myFolder.SubFolders
Debug.Print " mySubFolder: " & mySubFolder
For Each myFile In mySubFolder.Files
If "*" & myFile.Name & "*" Like "*" & strName3 & "*" Then
strJDName = myFile.Name
strDir = mySubFolder & "\"
strJDFile = strDir & strJDName
recurse = strJDFile
Exit Function
Else
Debug.Print " myFile.name: " & myFile.Name
End If
Next
recurse = recurse(mySubFolder.Path, strname, strName3)
Next
End Function
Here is a routine you may be able to adapt to your use, if you are running Excel under Windows.
Pick a base folder using the Excel folder picker routine
Enter a file name mask (eg: Book1.xls*)
Uses the Dir command window command to check all the folders and subfolders for files that start with Book1.xls
The results of the command are written to a temporary file (which is deleted at the end of the macro)
There is a way to write it directly to a VBA variable, but I see too much screen flicker when I've done that.
The results are then collected into a vba array, and written to a worksheet, but you can do whatever you want with the results.
Option Explicit
'set references to
' Microsoft Scripting Runtime
' Windows Script Host Object model
Sub FindFile()
Dim WSH As WshShell, lErrCode As Long
Dim FSO As FileSystemObject, TS As TextStream
Dim sTemp As String
Dim sBasePath As String
Dim vFiles As Variant, vFullList() As String
Dim I As Long
Dim sFileName As String
sTemp = Environ("Temp") & "\FileList.txt"
'Select base folder
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
If .Show = -1 Then 'if OK is pressed
sBasePath = .SelectedItems(1)
Else
Exit Sub
End If
End With
'File name mask
sFileName = InputBox("Entire File Mask", "File Finder")
Set WSH = New WshShell
lErrCode = WSH.Run("CMD /c dir """ & sBasePath & "\*" & sFileName & """ /A-D /B /S > " & sTemp, xlHidden, True)
If Not lErrCode = 0 Then
MsgBox "Problem Reading Directory" & _
vbLf & "Error Code " & lErrCode
Exit Sub
End If
Set FSO = New FileSystemObject
Set TS = FSO.OpenTextFile(sTemp, ForReading, False, TristateFalse)
vFiles = Split(TS.ReadAll, vbLf)
TS.Close
FSO.DeleteFile sTemp
Set FSO = Nothing
Set WSH = Nothing
ReDim vFullList(1 To UBound(vFiles), 1 To 1)
For I = 1 To UBound(vFiles)
vFullList(I, 1) = vFiles(I)
Next I
Dim rDest As Range
Set rDest = Cells(1, 2).Resize(UBound(vFullList, 1), UBound(vFullList, 2))
With rDest
.EntireColumn.Clear
.Value = vFullList
.EntireColumn.AutoFit
End With
End Sub
I have a macro that works to create emails, attach files. It runs and I use a recursive function to search through the directory to find files, match them to a field in the spreadsheet, and then attach them once found. It works and has worked for a while. However, they have added a level in the directory and now for some reason, it will not work. I am adding here the recursive section only, as that is where the error happens.
EDIT: For some reason when running from this new, higher level, it skips all the files that have numbers in the filename. Those filename numbers are what the macro uses to compare against the number in the field, so when it skips them it fails. So why would it skip them now, but work fine when running from the next subfolder down from the root directory?
Here is a sample directory to show how it looks, with Division being the root top folder. SubfolderD is where I want it to get to, find the data:
Division-->SubfolderA-->Subfolder2-->Subfolder3-->Etc
Division-->SubfolderB-->Subfolder2-->Subfolder3-->Etc
Division-->SubfolderC-->Subfolder2-->Subfolder3-->Etc
Division-->SubfolderD-->Subfolder2-->Subfolder3-->Etc
I can adjust the function to search at the SubfolderD and it will find the files. The issue is that new folders will be added and the files to be found may be in the other folders. So I need to get it to work from the Division folder consistently. I have stepped through the sub with F8 and I have looked at the debug print in the Immediate window. It seems to get all the way through SubfolderC, but then stops and for some reason seems to give up. Any thoughts? Thanks
Function recurse(sPath As String, strname As String, strName3 As String)
Dim FSO As New FileSystemObject
Dim myFolder As Scripting.Folder
Dim mySubFolder As Scripting.Folder
Dim myFile As Scripting.file
Dim strJDFile As String
Dim strDir As String
Dim strJDName As String
Set myFolder = FSO.GetFolder(sPath)
' strName = Range("a2").Offset(0, 3)
strName3 = Replace(strName3, "/", " ")
For Each mySubFolder In myFolder.SubFolders
Debug.Print " mySubFolder: " & mySubFolder
For Each myFile In mySubFolder.Files
If "*" & myFile.Name & "*" Like "*" & strName3 & "*" Then
strJDName = myFile.Name
strDir = mySubFolder & "\"
strJDFile = strDir & strJDName
recurse = strJDFile
Exit Function
Else
Debug.Print " myFile.name: " & myFile.Name
End If
Next
recurse = recurse(mySubFolder.Path, strname, strName3)
Next
End Function
Edited to Post Entire Sub:
Option Compare Text
Sub Recursive()
'
'
Dim OutApp As Object
Dim OutMail As Object
Dim cell As Range
Dim strDir As String
Dim strFilename As String
Dim sigString As String
Dim strBody As String
Dim strname As String
Dim strName1 As String
Dim strName3 As String
Dim strDept As String
Dim strName2 As String
Dim LR As Long
Dim oItem As Object
Dim dteSat As Date
Dim nextSat As Date
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
sigString = Environ("appdata") & _
"\Microsoft\Signatures\Test.htm"
If Dir(sigString) <> "" Then
signature = GetBoiler(sigString)
Else
signature = ""
End If
Select Case Time
Case 0.25 To 0.5
GreetTime = "Good morning"
Case 0.5 To 0.71
GreetTime = "Good afternoon"
Case Else
GreetTime = "Good evening"
End Select
With ActiveSheet
With .Columns(2)
.NumberFormat = "General"
.TextToColumns Destination:=.Cells(1), _
DataType:=xlFixedWidth, fieldinfo:=Array(0, 1)
End With
End With
With Item
K = Weekday(Today)
dteSat = Now() + (10 - K)
nextSat = Date + 7 - Weekday(Date, vfSaturday)
End With
LR = ActiveSheet.UsedRange.Rows.Count
Columns("z:z").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("z2") = "Yes"
Range("z2").AutoFill Destination:=Range("z2:z" & LR)
For Each cell In Columns("J").Cells.SpecialCells(xlCellTypeConstants)
If cell.Value Like "?*#?*.?*" And _
LCase(Cells(cell.Row, "z").Value) = "yes" Then
Set OutMail = OutApp.CreateItem(0)
With OutMail
strName3 = Cells(cell.Row, "b").Value
strName1 = Cells(cell.Row, "d").Value
strName2 = Trim(Split(strName1, " ")(1))
strname = Cells(cell.Row, "a").Value
strJDFile = recurse("z:\Division", strname, strName3)
strBody = "<Font Face=calibri><br><br>The form needs to be completed no later " & _
"than next week. <br><br>" & _
.SentOnBehalfOfName = ""
.To = cell.Value
.Subject = "Please Reply"
.HTMLBody = "<Font Face=calibri>" & GreetTime & " " & strName1 & ", " & strBody & "<br>" & signature
.Attachments.Add strJDFile
.Display 'Or use Send
End With
Set OutMail = Nothing
End If
Next cell
End Sub
Function GetBoiler(ByVal sFile As String) As String
Dim FSO As Object
Dim ts As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Set ts = FSO.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.ReadAll
ts.Close
End Function
Function recurse(sPath As String, strname As String, strName3 As String)
Dim FSO As New FileSystemObject
Dim myFolder As Scripting.Folder
Dim mySubFolder As Scripting.Folder
Dim myFile As Scripting.file
Dim strJDFile As String
Dim strDir As String
Dim strJDName As String
Set myFolder = FSO.GetFolder(sPath)
' strName = Range("a2").Offset(0, 3)
strName3 = Replace(strName3, "/", " ")
For Each mySubFolder In myFolder.SubFolders
Debug.Print " mySubFolder: " & mySubFolder
For Each myFile In mySubFolder.Files
If "*" & myFile.Name & "*" Like "*" & strName3 & "*" Then
strJDName = myFile.Name
strDir = mySubFolder & "\"
strJDFile = strDir & strJDName
recurse = strJDFile
Exit Function
Else
Debug.Print " myFile.name: " & myFile.Name
End If
Next
recurse = recurse(mySubFolder.Path, strname, strName3)
Next
End Function
just wanted to let you know I figured it out. Everything was working the way it should but it was still not finding, skipping certain files. It appears there was an issue with this particular problem in Office. I updated MS Office (all applications) along with Windows to the latest win10 version and it worked!
Thanks again
I have macro, if I put in cell E1 name of the file, macro search trough C:\Users\Marek\Desktop\Makro\ directory, find it and put the needed values in specific cells of my original file with macro.
Is it possible to make this work without specific folder location? I need something that can search trough C:\Users\Marek\Desktop\Makro\ with many subfolders in it.
My code:
Sub Zila1()
Dim SaveDriveDir As String, MyPath As String
Dim FName As Variant
Dim YrMth As String
SaveDriveDir = CurDir
MyPath = Application.DefaultFilePath 'or use "C:\Data"
ChDrive MyPath
ChDir MyPath
FName = Sheets("Sheet1").Range("E1").Text
If FName = False Then
'do nothing
Else
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"A16:A17", Sheets("Sheet1").Range("B2:B3"), True, False
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"AE23:AE24", Sheets("Sheet1").Range("B3:B4"), True, False
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"AE26:AE27", Sheets("Sheet1").Range("B4:B5"), True, False
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"AQ59:AQ60", Sheets("Sheet1").Range("B5:B6"), True, False
GetData "C:\Users\Marek\Desktop\Makro\" & FName & ".xls", "Vystupna_kontrola", _
"AR65:AR66", Sheets("Sheet1").Range("B6:B7"), True, False
End If
ChDrive SaveDriveDir
ChDir SaveDriveDir
End Sub
Just for fun, here's a sample with a recursive function which (I hope) should be a bit simpler to understand and to use with your code:
Function Recurse(sPath As String) As String
Dim FSO As New FileSystemObject
Dim myFolder As Folder
Dim mySubFolder As Folder
Set myFolder = FSO.GetFolder(sPath)
For Each mySubFolder In myFolder.SubFolders
Call TestSub(mySubFolder.Path)
Recurse = Recurse(mySubFolder.Path)
Next
End Function
Sub TestR()
Call Recurse("D:\Projets\")
End Sub
Sub TestSub(ByVal s As String)
Debug.Print s
End Sub
Edit: Here's how you can implement this code in your workbook to achieve your objective.
Sub TestSub(ByVal s As String)
Dim FSO As New FileSystemObject
Dim myFolder As Folder
Dim myFile As File
Set myFolder = FSO.GetFolder(s)
For Each myFile In myFolder.Files
If myFile.Name = Range("E1").Value Then
Debug.Print myFile.Name 'Or do whatever you want with the file
End If
Next
End Sub
Here, I just debug the name of the found file, the rest is up to you. ;)
Of course, some would say it's a bit clumsy to call twice the FileSystemObject so you could simply write your code like this (depends on wether you want to compartmentalize or not):
Function Recurse(sPath As String) As String
Dim FSO As New FileSystemObject
Dim myFolder As Folder
Dim mySubFolder As Folder
Dim myFile As File
Set myFolder = FSO.GetFolder(sPath)
For Each mySubFolder In myFolder.SubFolders
For Each myFile In mySubFolder.Files
If myFile.Name = Range("E1").Value Then
Debug.Print myFile.Name & " in " & myFile.Path 'Or do whatever you want with the file
Exit For
End If
Next
Recurse = Recurse(mySubFolder.Path)
Next
End Function
Sub TestR()
Call Recurse("D:\Projets\")
End Sub
This sub will populate a Collection with all files matching the filename or pattern you pass in.
Sub GetFiles(StartFolder As String, Pattern As String, _
DoSubfolders As Boolean, ByRef colFiles As Collection)
Dim f As String, sf As String, subF As New Collection, s
If Right(StartFolder, 1) <> "\" Then StartFolder = StartFolder & "\"
f = Dir(StartFolder & Pattern)
Do While Len(f) > 0
colFiles.Add StartFolder & f
f = Dir()
Loop
If DoSubfolders then
sf = Dir(StartFolder, vbDirectory)
Do While Len(sf) > 0
If sf <> "." And sf <> ".." Then
If (GetAttr(StartFolder & sf) And vbDirectory) <> 0 Then
subF.Add StartFolder & sf
End If
End If
sf = Dir()
Loop
For Each s In subF
GetFiles CStr(s), Pattern, True, colFiles
Next s
End If
End Sub
Usage:
Dim colFiles As New Collection
GetFiles "C:\Users\Marek\Desktop\Makro\", FName & ".xls", True, colFiles
If colFiles.Count > 0 Then
'work with found files
End If
If this helps, you can also use FileSystemObject to retrieve all subfolders of a folder.
You need to check the reference "Microsot Scripting Runtime" to get Intellisense and use the "new" keyword.
Sub GetSubFolders()
Dim fso As New FileSystemObject
Dim f As Folder, sf As Folder
Set f = fso.GetFolder("D:\Proj\")
For Each sf In f.SubFolders
'Code inside
Next
End Sub
I actually just found this today for something I'm working on. This will return file paths for all files in a folder and its subfolders.
Dim colFiles As New Collection
RecursiveDir colFiles, "C:\Users\Marek\Desktop\Makro\", "*.*", True
Dim vFile As Variant
For Each vFile In colFiles
'file operation here or store file name/path in a string array for use later in the script
filepath(n) = vFile
filename = fso.GetFileName(vFile) 'If you want the filename without full path
n=n+1
Next vFile
'These two functions are required
Public Function RecursiveDir(colFiles As Collection, strFolder As String, strFileSpec As String, bIncludeSubfolders As Boolean)
Dim strTemp As String
Dim colFolders As New Collection
Dim vFolderName As Variant
strFolder = TrailingSlash(strFolder)
strTemp = Dir(strFolder & strFileSpec)
Do While strTemp <> vbNullString
colFiles.Add strFolder & strTemp
strTemp = Dir
Loop
If bIncludeSubfolders Then
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
End Function
Public Function TrailingSlash(strFolder As String) As String
If Len(strFolder) > 0 Then
If Right(strFolder, 1) = "\" Then
TrailingSlash = strFolder
Else
TrailingSlash = strFolder & "\"
End If
End If
End Function
This is adapted from a post by Ammara Digital Image Solutions.(http://www.ammara.com/access_image_faq/recursive_folder_search.html).