how to include file system object properties in excel vba dynamic array - arrays

I am trying to work out how to use filesystemobject to include date created, date modified, size, path, file/folder names of files and folders into an excel vba dynamic array so that it automatically expands or contracts to the list of files/folders.
In addition, I am trying to make a list of excluded folder paths so that when I click search, only those folder paths and its files are excluded from the result list, but other folders and its files are shown. Is it possible to make a list of folder paths which will exclude deeper nested folder subfolders?
For example, In this folder C:\test with spaces\ (see image) folder structure I want to exclude the file in C:\test with spaces\subfolder 1\2ndlevelsubfolder1\ including "2ndlevelsubfolder1", but I want all other folders paths to be displayed. How can I do this with vba?
Finally, I also want to make this list recursive, so that every time I add/remove the excluded list of folder paths, new entries will be added right after the previous list. I have these functions made in different excel workbooks but the only problem is incorporating them together into one code. I am showing you my code from 2 workbooks:
This code is for recursive listing:
Option Explicit
Sub SomeSub()
Call GetFiles("\\?\[INSERT PARENT FOLDER PATH HERE]") 'attach "\\?\" at the beginning for long folder path names! ex..'GetFiles("\\?\INSERT..."
'can also list multiple "Call GetFiles("\\?\[insert new folder path here]")" to list multiple folder paths all at once
End Sub
Sub GetFiles(ByVal path As String)
Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Dim folder As Object
Set folder = FSO.GetFolder(path)
Dim SubFolder As Object
Dim file As Object
For Each SubFolder In folder.Subfolders
GetFiles (SubFolder.path)
Next SubFolder
Range("A1") = "parent folder"
'Range("A1").Offset(0, 1) = "FILE/FOLDER PATH"
Range("A1").Offset(0, 3) = "FILE or FOLDER"
Range("A1").Offset(0, 4) = "DATE CREATED"
Range("A1").Offset(0, 5) = "DATE MODIFIED"
Range("A1").Offset(0, 6) = "SIZE"
Range("A1").Offset(0, 7) = "TYPE"
Range("A" & Rows.Count).End(xlUp).Offset(1, 0) = Replace(folder, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 1) = Replace(folder, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 2) = folder.Name
Range("A" & Rows.Count).End(xlUp).Offset(0, 3) = "FOLDER"
Range("A" & Rows.Count).End(xlUp).Offset(0, 4) = folder.datecreated
Range("A" & Rows.Count).End(xlUp).Offset(0, 5) = folder.DateLastModified
For Each SubFolder In folder.Subfolders
'Range("A" & Rows.Count).End(xlUp).Offset(1, 0) = Replace(subfolder.path, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 1) = Replace(folder, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 2) = subfolder.Name
'Range("A" & Rows.Count).End(xlUp).Offset(0, 3) = "FOLDER"
'Range("A" & Rows.Count).End(xlUp).Offset(0, 4) = subfolder.datecreated
'Range("A" & Rows.Count).End(xlUp).Offset(0, 5) = subfolder.DateLastModified
Next SubFolder
For Each file In folder.Files
Range("A" & Rows.Count).End(xlUp).Offset(1, 0) = Replace(file.path, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 1) = Replace(folder, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 2) = file.Name
Range("A" & Rows.Count).End(xlUp).Offset(0, 3) = "FILE"
Range("A" & Rows.Count).End(xlUp).Offset(0, 4) = file.datecreated
Range("A" & Rows.Count).End(xlUp).Offset(0, 5) = file.DateLastModified
Range("A" & Rows.Count).End(xlUp).Offset(0, 6) = file.Size
Range("A" & Rows.Count).End(xlUp).Offset(0, 7) = file.Type
Next file
With Range("E:F")
.NumberFormat = "dddd mmmm dd, yyyy H:mm:ss AM/PM" 'long file date and time
End With
Set FSO = Nothing
Set folder = Nothing
Set SubFolder = Nothing
Set file = Nothing
End Sub
This is the excluded folder name list code in cell A3 only the names are inserted at cell A3 seperated by commas with no spaces after the comma. I want folder paths at any subfolder level to be excluded, not just names at the 1st level
Option Explicit
'http://www.ozgrid.com/forum/showthread.php?t=158478
Dim iRow As Long
Sub ListFiles()
Dim lRow As Long
iRow = 11
lRow = Range("B" & Rows.Count).End(xlUp).Row
If lRow >= iRow Then
Range("B" & iRow & ":E" & Range("B" & Rows.Count).End(xlUp).Row).Clear
End If
Call ListMyFiles(Range("A1"), Range("A2"), Range("A3")) 'Cell A1 is the parent directory, A2 is include subfolders as false or true _
cell A3 is the exclude folder names within the parent directory _
which only works in the 1st level not deeper nested levels
Application.GoTo Range("B3"), True
End Sub
Sub ListMyFiles(mySourcePath As String, IncludeSubfolders As String, _
Optional excludedSubfolders As String = " ")
Dim myObject As Scripting.FileSystemObject
Dim mySource As Scripting.folder, myFile As Variant
Dim myfolder As Variant
Dim iCol As Integer
Dim mySubFolder As Scripting.folder, v As Variant
Dim asf() As String, sf As String
asf() = Split(Replace(excludedSubfolders, ", ", ","), ",")
Set myObject = New Scripting.FileSystemObject
If Right(mySourcePath, 1) <> "\" Then mySourcePath = mySourcePath + "\"
Set mySource = myObject.GetFolder(mySourcePath)
On Error Resume Next
For Each mySubFolder In mySource.SubFolders
iCol = 1
Cells(iRow, iCol).Value = mySubFolder.Path
iCol = iCol + 1
Cells(iRow, iCol).Value = mySubFolder.Name
iRow = iRow + 1
Next mySubFolder
If IncludeSubfolders Then
For Each mySubFolder In mySource.SubFolders
If excludedSubfolders = " " Then
Call ListMyFiles(mySubFolder.Path, True)
Else
sf = Trim(Right(mySubFolder.Path, Len(mySubFolder.Path) - Len(mySourcePath)))
If IndexStrArray(asf(), sf) = -1 Then Call ListMyFiles(mySubFolder.Path, True)
End If
Next
End If
End Sub
'val is not case sensitive
Function IndexStrArray(vArray() As String, sVal As String) As Long
Dim v As Variant, i As Long
On Error GoTo Minus1
For i = 0 To UBound(vArray)
If LCase(vArray(i)) = LCase(sVal) Then
IndexStrArray = i
Exit Function
End If
Next i
Minus1:
IndexStrArray = -1
End Function
I hope this has shed some light on what I want to achieve. Thank you & hope to hear from you soon.

Not sure it'll 100% match your needs.
You should use collections, and recursive sub, like this (not fully tested, it might needs some corrections):
' List of complete path of files in folder / subfolders
' Needs to add "Microsoft Scripting Runtime" reference to your file
Sub FolderFilesPath(ByVal pFolder As String, ByRef pColFiles As Collection, _
Optional ByVal pGetSubFolders As Boolean, Optional ByVal pFilter As Collection)
Dim sFolder As String
Dim oFSO As New FileSystemObject
Dim oFolder, oSubFolder As Folder
Dim oFile As File
sFolder = IIf(Right(pFolder, 1) <> "\", pFolder & "\", pFolder)
Set oFolder = oFSO.GetFolder(sFolder)
If Not ExistsInCollection(pFilter, oFolder) Then
For Each oFile In oFolder.Files
pColFiles.Add oFile
Next oFile
If pGetSubFolders Then
For Each oSubFolder In oFolder.SubFolders
FolderFilesPath oSubFolder.Path, pColFiles, pGetSubFolders,
pFilter
Next
End If
End If
End Sub
' Vba collection contains
Function ExistsInCollection(col As Collection, key As Variant) As Boolean
On Error GoTo err
ExistsInCollection = True
IsObject (col.Item(key))
Exit Function
err:
ExistsInCollection = False
End Function
'------------------------------------------------------------------------------
Sub TestMe()
Dim colFiles As New Collection, sFilePath As Variant
Dim colExcludedFolders As New Collection
With colExcludedFolders
.Add "C:\test with spaces\subfolder 1\"
End With
FolderFilesPath ThisWorkbook.Path, colFiles, True, colExcludedFolders
' colFiles contains filtered files
For Each sFilePath In colFiles
With sFilePath
Debug.Print .Path & " - " & .Name & " - " & .DateCreated
End With
Next sFilePath
End Sub

Now i am getting Run-time error '28': Out of stack space
What is wrong with this code?

Related

vba wscript.shell copy file from folder to another folder based on cell path or filename

I want to do it with vba wscript.shell because copying files is faster and I want to copy files based on path or filename in excel cell based on the selection in column "E" and output the destination folder using "msoFileDialogFolderPicker"
I have sample code but need to change.
Sub copy()
xDFileDlg As FileDialog
xDPathStr As Variant
sn = Filter(Split(CreateObject("wscript.shell").exec("cmd /c dir C:\copy\*.* /b /s").stdout.readall, vbCrLf), "\")
'For j = 0 To UBound(sn)
'If DateDiff("d", FileDateTime(sn(j)), Date) > 30 Then sn(j) = ""
'Next
sn = Filter(sn, "\")
For j = 0 To UBound(sn)
FileCopy sn(j), "C:\destcopy" & Mid(sn(j), 2)
Next
Set xDFileDlg = Application.FileDialog(msoFileDialogFolderPicker)
xDFileDlg.Title = "Please select the destination folder:"
If xDFileDlg.Show <> -1 Then Exit Sub
xDPathStr = xDFileDlg.SelectedItems.Item(1) & "\"
End Sub
Thanks
roy
Please, test the next code. It assumes that you need to select the destination folder for copying of all files there. Otherwise, some milliseconds saved by VBScript object mean too little against the necessary seconds to browse for each file destination folder to be copied. But, if this is what you want, I can easily adapt the code to do that:
Sub copyFiles()
Dim sh As Worksheet, lastR As Long, arrA, i As Long, k As Long
Dim fileD As FileDialog, strDestFold As String, FSO As Object
Set sh = ActiveSheet
lastR = sh.Range("A" & sh.rows.count).End(xlUp).row ' last row on A:A column
arrA = sh.Range("A2:E" & lastR).Value2 'place the range in an array for faster iteration
Set FSO = CreateObject("Scripting.FileSystemObject")
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Please select the destination folder!"
.AllowMultiSelect = False
If .Show = -1 Then
strDestFold = .SelectedItems.Item(1) & "\" 'select the destination folder
End If
End With
If strDestFold = "" Then Exit Sub 'in case of not selecting any folder
For i = 1 To UBound(arrA)
If UCase(arrA(i, 5)) = "V" Then 'copy the file only if a "V" exists in column E:E
If FSO.FileExists(arrA(i, 1)) Then 'check if the path in excel is correct
FSO.CopyFile arrA(i, 1), strDestFold, True 'copy the file (True, to overwrite the file if it exists)
k = k + 1
Else
MsgBox arrA(i, 1) & " file could not be found." & vbCrLf & _
"Please, check the spelling and correct the file full path!", vbInformation, _
"File does not exist..."
End If
End If
Next i
MsgBox "Copied " & k & " files in " & strDestFold, , "Ready..."
End Sub

Excel VBA - Recursive files searching all Folders (drill down) writing results to same array doesn't work so well as a collection

This is my first post - I hope it is a good one :)
A small task for home, is I would like an array of all the file paths in a folder (and it's sub folders) but only for PDF or a file type that I tell it to filter on.
I like arrays better (and it can write to a Range very quickly), I know I can convert my first example of code from a collection to an Array but I would like to learn and understand the logic / syntax of how to implement my example 1 but using Arrays only.
Example 1 works (I left out the other bit of code I use to Debug.Print it) :
Sub GetAllFilePaths(StartFolder As String, Pattern As String, _
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
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
GetAllFilePaths CStr(S), Pattern, colFiles
Next S
End Sub
Example 2 doesn't quite work, it seems to loop in how I want it but overwrites the array not adds to it, so doesn't get all the PDF files I know is in the deep sub folders.
I think it is the way I handled adding to the array, the resizing and at which index I add the new value, I have looked.. everywhere for some help even here
Recursive search of file/folder structure,
https://excelvirtuoso.net/2017/02/07/multi-dimensional-arrays/,
VBA macro that search for file in multiple subfolders,
I know the logic isn't right in the bit but cant seem to figure out it out, any help please..
Example 2 code (I put in how I call it and use Debug.Print to test it):
Option Explicit
Sub GetAllFilePaths(StartFolder As String, Pattern As String, ByRef allFilePaths As Variant, ByRef allFileNames As Variant)
Dim FNum As Integer
Dim mainFolder As Object
Dim pathFile As String
Dim subFoldersRecurs As New Collection, SubPath
Dim SubFilePath As String
If Right(StartFolder, 1) <> "\" Then StartFolder = StartFolder & "\"
pathFile = Dir(StartFolder & Pattern)
Do While Len(pathFile) > 0
FNum = FNum + 1
ReDim Preserve allFileNames(1 To FNum)
ReDim Preserve allFilePaths(1 To FNum)
allFileNames(FNum) = pathFile
allFilePaths(FNum) = StartFolder & pathFile
pathFile = Dir()
Loop
SubFilePath = Dir(StartFolder, vbDirectory)
Do While Len(SubFilePath) > 0
If SubFilePath <> "." And SubFilePath <> ".." Then
If (GetAttr(StartFolder & SubFilePath) And vbDirectory) <> 0 Then
subFoldersRecurs.Add StartFolder & SubFilePath
End If
End If
SubFilePath = Dir()
Loop
For Each SubPath In subFoldersRecurs
GetAllFilePaths CStr(SubPath), Pattern, allFilePaths, allFileNames
Next SubPath
End Sub
Sub PDFfilestoCollall()
Dim pdfFilePaths() As Variant
Dim pdfFileNames() As Variant
Call GetAllFilePaths("C:\Users\adg\Downloads\test folder of files for ingest\", "*.PDF", pdfFilePaths, pdfFileNames)
Dim CollEntry As Variant
For Each CollEntry In pdfFilePaths
Debug.Print CollEntry
Thanks,
ADG
I've refactored you code here.
Sub GetAllFilePaths(ByVal StartFolder As String, ByVal Pattern As String, _
ByRef arrFiles() As String, Optional ByRef AddToArrayAt As Long = -1)
Dim f As String
Dim sf As String
Dim subF As Collection
Dim S
Dim AddedFiles As Boolean
If Right(StartFolder, 1) <> "\" Then StartFolder = StartFolder & "\"
If AddToArrayAt < 0 Then AddToArrayAt = LBound(arrFiles)
f = Dir(StartFolder & Pattern)
Do While Len(f) > 0
AddedFiles = True
If AddToArrayAt > UBound(arrFiles) Then ReDim Preserve arrFiles(LBound(arrFiles) To UBound(arrFiles) + 100)
arrFiles(AddToArrayAt) = StartFolder & f
AddToArrayAt = AddToArrayAt + 1
f = Dir()
Loop
If AddedFiles Then ReDim Preserve arrFiles(LBound(arrFiles) To AddToArrayAt - 1)
Set subF = New Collection
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
GetAllFilePaths CStr(S), Pattern, arrFiles, AddToArrayAt
Next S
End Sub
Sub test()
Dim pdfFileNames() As String
ReDim pdfFileNames(1 To 100)
GetAllFilePaths "C:\Data\", "*.PDF", pdfFileNames
Dim i As Long
For i = LBound(pdfFileNames) To UBound(pdfFileNames)
Debug.Print pdfFileNames(i)
Next
End Sub
Couple of points to note:
I'm Redim Preserve'ing the arrFiles array in lots of 100 because this operation is quite slow
I've retained a Collection internally for the folders loop, as it's quite convenient and not exposed to the calling routine
I've not studied your Dir's so I make no claims on their efficacy or efficiency

Deleting directory in an array

I have this code that gets all file types.
Dim file as variant
file = Application.GetOpenFilename("All Files, *.*", , "Select File", , True)
Then I have to print it in the cells on a sheet.
For i = 1 To UBound(file)
lRow = Cells(Rows.count, 15).End(xlUp).Row
lRow = lRow + 1
ThisWorkbook.Sheets("Main").Range("O" & lRow).Value = CStr(file(i))
Next i
but what I want is first check the contents of the array. If the array has this file type, then I have to remove it in the arraylist. After that, a message will pop out that this files are removed.
dim arr() as string
arr = Split("ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|hta|inf|ins|isp|its|js|jse|" _
& "ksh|lnk|mad|maf|mag|mam|maq|mar|mas|mat|mau|mav|maw|mda|mdb|mde|mdt|mdw|mdz|msc|msh|msh1|msh2|" _
& "mshxml|msh1xml|msh2xml|ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|" _
& "hta|msi|msp|mst|ops|pcd|pif|plg|prf|prg|pst|reg|scf|scr|sct|shb|shs|ps1|ps1xml|ps2|ps2xml|psc1|psc2|tmp|url|vb|vbe|vbs|vsmacros|vsw|ws|wsc|wsf|wsh|xnk", "|")
I just don't know where I have to start. I have found a little bit same problem here in this post, but I just can't understand it. Thanks!
You can use a RegExp and a varaint array to do this quickly
This code looks for path... dot extension end string so it is more robust than your current array which may remove files based on the path name rather than file type
Sub B()
Dim fName As Variant
Dim objRegex As Object
Dim lngCnt As Long
Dim rng1 As Range
Set objRegex = CreateObject("vbscript.regexp")
On Error Resume Next
fName = Application.GetOpenFilename("All Files, *.*", , "Select file", , True)
If Err.Number <> 0 Then Exit Sub
On Error GoTo 0
With objRegex
.Pattern = ".*\.(ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|hta|inf|ins|isp|its|js|jse|" _
& "ksh|lnk|mad|maf|mag|mam|maq|mar|mas|mat|mau|mav|maw|mda|mdb|mde|mdt|mdw|mdz|msc|msh|msh1|msh2|" _
& "mshxml|msh1xml|msh2xml|ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|" _
& "hta|msi|msp|mst|ops|pcd|pif|plg|prf|prg|pst|reg|scf|scr|sct|shb|shs|ps1|ps1xml|ps2|ps2xml|psc1|psc2|tmp|url|vb|vbe|vbs|vsmacros|vsw|ws|wsc|wsf|wsh|xnk)$"
`replace matching file types with blank array entries
For lngCnt = 1 To UBound(fName)
fName(lngCnt) = .Replace(fName(lngCnt), vbNullString)
Next
End With
Set rng1 = Cells(Rows.Count, 15).End(xlUp).Offset(1,0)
'dump array to sheet
rng1.Resize(UBound(fName), 1) = Application.Transpose(fName)
` remove blank entries
On Error Resume Next
rng1.SpecialCells(xlCellTypeBlanks).Delete xlUp
On Error GoTo 0
End Sub
One way would be to check that the extension it's not present in the blacklist with InStr:
Const exts = _
".ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp.gadget" & _
".hlp.hta.inf.ins.isp.its.js.jse.ksh.lnk.mad.maf.mag.mam.maq.mar.mas.mat" & _
".mau.mav.maw.mda.mdb.mde.mdt.mdw.mdz.msc.msh.msh1.msh2.mshxml.msh1xml" & _
".msh2xml.ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp" & _
".gadget.hlp.hta.msi.msp.mst.ops.pcd.pif.plg.prf.prg.pst.reg.scf.scr.sct" & _
".shb.shs.ps1.ps1xml.ps2.ps2xml.psc1.psc2.tmp.url.vb.vbe.vbs.vsmacros.vsw" & _
".ws.wsc.wsf.wsh.xnk."
Dim file As Variant
file = Application.GetOpenFilename("All Files, *.*", , "Select File", , True)
Dim i As Long, data(), count As Long, ext As String
ReDim data(1 To UBound(file) + 1, 1 To 1)
' filter the list
For i = LBound(file) To UBound(file)
ext = LCase(Mid(file(i), InStrRev(file(i), ".")))
If InStr(1, exts, ext & ".") = 0 Then ' if not blacklisted
count = count + 1
data(count, 1) = file(i)
End If
Next
' copy the filtered list to the next available row in column "O"
If count Then
With ThisWorkbook.Sheets("Main").Cells(Rows.count, "O").End(xlUp)
.Offset(1).Resize(count).Value = data
End With
End If

VBA Directory File Search using list within Excel

I'm currently trying to edit a macro a colleague of mine currently uses, the script currently opens a message box that allows you to enter in a string, which is then searched for and results are pasted into the workbook. I would like to change this so it searches for a list already within the spreadsheet, and then for the results to be pasted on the next worksheet. I'm not sure if this is actually possible or not, which is where my main struggle is. Below is the current code, I assume all that is needed is for the variable range to be placed in that stars "msg = "Enter file name and Extension"
Sub Filesearch()
Dim myDir As String, temp(), myList, myExtension As String
Dim SearchSubFolders As Boolean, Rtn As Integer, msg As String
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show Then
myDir = .SelectedItems(1)
End If
End With
msg = "Enter File name and Extension" & vbLf & "following wild" & _
" cards can be used" & vbLf & "* # ?"
myExtension = Application.InputBox(msg)
If (myExtension = "False") + (myExtension = "") Then Exit Sub
Rtn = MsgBox("Include Sub Folders ?", vbYesNo)
SearchSubFolders = Rtn = 6
myList = SearchFiles(myDir, myExtension, 0, temp(), SearchSubFolders)
If Not IsError(myList) Then
Sheets(1).Cells(1).Resize(UBound(myList, 2), 2).Value = _
Application.Transpose(myList)
Else
MsgBox "No file found"
End If
End Sub
Private Function SearchFiles(myDir As String _
, myFileName As String, n As Long, myList() _
, Optional SearchSub As Boolean = False) As Variant
Dim fso As Object, myFolder As Object, myFile As Object
Set fso = CreateObject("Scripting.FileSystemObject")
For Each myFile In fso.getfolder(myDir).Files
Select Case myFile.Attributes
Case 2, 4, 6, 34
Case Else
If (Not myFile.Name Like "~$*") _
* (myFile.Path & "\" & myFile.Name <> ThisWorkbook.FullName) _
* (UCase(myFile.Name) Like UCase(myFileName)) Then
n = n + 1
ReDim Preserve myList(1 To 2, 1 To n)
myList(1, n) = myDir
myList(2, n) = myFile.Name
End If
End Select
Next
If SearchSub Then
For Each myFolder In fso.getfolder(myDir).subfolders
SearchFiles = SearchFiles(myFolder.Path, myFileName, _
n, myList, SearchSub)
Next
End If
SearchFiles = IIf(n > 0, myList, CVErr(xlErrRef))
End Function
Suggest the use of Defined Name Ranges to hold the user maintained list (as show in the picture below)
Let’s add a worksheet for user input of the requirements called “_Tables”.
Then create Defined Name Ranges, for users to enter the requirements, called "_Path", "_Files" and "_SubFldrs"
Then replace all the user’s input in current code
REPLACE THIS
''' With Application.FileDialog(msoFileDialogFolderPicker)
''' If .Show Then
''' myDir = .SelectedItems(1)
''' End If
''' End With
''' msg = "Enter File name and Extension" & vbLf & "following wild" & _
''' " cards can be used" & vbLf & "* # ?"
''' myExtension = Application.InputBox(msg)
''' If (myExtension = "False") + (myExtension = "") Then Exit Sub
''' Rtn = MsgBox("Include Sub Folders ?", vbYesNo)
''' SearchSubFolders = Rtn = 6
with this in order to read the requirements from the worksheet "_Tables"
Set WshLst = ThisWorkbook.Sheets("_Tables")
sPath = WshLst.Range("_Path").Value2
aFleKey = WshLst.Range("_Files").Value2
bSbFldr = UCase(WshLst.Range("_SubFldrs").Value2) = UCase("YES")
aFleKey = WorksheetFunction.Transpose(aFleKey)
then Process the lists
See below the entire code below. It's necessary to have the statement Option Base 1 at the top of the module
Option Explicit
Option Base 1
Sub Fle_FileSearch_List()
Dim WshLst As Worksheet
Dim sPath As String
Dim aFleKey As Variant, vFleKey As Variant
Dim bSbFldr As Boolean
Dim vFleLst() As Variant
Dim lN As Long
Set WshLst = ThisWorkbook.Sheets("_Tables")
sPath = WshLst.Range("_Path").Value2
aFleKey = WshLst.Range("_Files").Value2
bSbFldr = UCase(WshLst.Range("_SubFldrs").Value2) = UCase("YES")
aFleKey = WorksheetFunction.Transpose(aFleKey)
Rem To clear output location
ThisWorkbook.Sheets(1).Columns(1).Resize(, 2).Clear
Rem Process input list
For Each vFleKey In aFleKey
If (vFleKey <> "False") * (vFleKey <> "") Then
Call Fle_FileSearch_Fldrs(sPath, CStr(vFleKey), lN, vFleLst, bSbFldr)
End If: Next
Rem Validate Results & List Files found
If lN > 1 Then
ThisWorkbook.Sheets(1).Cells(1).Resize(UBound(vFleLst, 2), 2) _
.Value = Application.Transpose(vFleLst)
Else
MsgBox "No file found"
End If
End Sub
Also some adjustments to the function (now a procedure) to allow the process of the list.
Sub Fle_FileSearch_Fldrs(sPath As String, _
sFleKey As String, lN As Long, vFleLst() As Variant, _
Optional bSbFldr As Boolean = False)
Dim oFso As Object, oFolder As Object, oFile As Object
Set oFso = CreateObject("Scripting.FileSystemObject")
If lN = 0 Then
lN = 1 + lN
ReDim Preserve vFleLst(1 To 2, 1 To lN)
vFleLst(1, lN) = "Files Found - Path"
vFleLst(2, lN) = "Files Found - Name"
End If
For Each oFile In oFso.GetFolder(sPath).Files
Select Case oFile.Attributes
Case 2, 4, 6, 34
Case Else
If (Not oFile.Name Like "~$*") * _
(oFile.Path & "\" & oFile.Name <> ThisWorkbook.FullName) * _
(UCase(oFile.Name) Like UCase(sFleKey)) Then
lN = lN + 1
ReDim Preserve vFleLst(1 To 2, 1 To lN)
vFleLst(1, lN) = sPath
vFleLst(2, lN) = oFile.Name
End If: End Select: Next
If bSbFldr Then
For Each oFolder In oFso.GetFolder(sPath).subfolders
Call Fle_FileSearch_Fldrs(oFolder.Path, sFleKey, lN, vFleLst, bSbFldr)
Next: End If
End Sub

Activate windows of files stored in arrays, but getting subscript out of range error?

Sub Merge()
Dim File As String
Dim AllFiles(), Filename As Variant
Dim count, test, StartRow, LastRow, LastColumn As Long
Dim LastCell As Variant
test = 0
ChDir "C:\" 'Insert suitable directory for your computer ex:ChDir "C:\Users\Jerry Hou\" if file of interest is in "Jerry Hou" Folder
ReDim AllFiles(1)
Do
Application.EnableCancelKey = xlDisabled
File = Application.GetOpenFilename("XML Files (*.xml),*.xml", 1, "Select File to be Merged") 'Needs to select in Order to merge files
Application.EnableCancelKey = xlErrorHandler
If (File = "False") Then Exit Do
ReDim Preserve AllFiles(count) 'Preserve ?
AllFiles(count) = File 'File== file name and directory
count = (count + 1)
If (MsgBox("Select Another File To be Merged With?", vbQuestion + vbOKCancel, "Merge Files") = vbCancel) Then Exit Do
Loop 'Select Cancel in MsgBox to finish merge file(s) selection
If (count = 0) Then
MsgBox "No selection" 'If you hit Exit from open prompt window
Exit Sub
End If
For count = 0 To UBound(AllFiles)
MsgBox "User selected file name: " & AllFiles(count)
Next
test = count
For test = UBound(AllFiles) To LBound(AllFiles) Step -1
Workbooks.Open Filename:=AllFiles(test)
Next
ReDim AllFiles(count)
test = 2
Do While (test <= count)
Filename = AllFiles(test)
Workbooks(AllFiles(test)).Activate 'ERROR Brings 2nd file that the user had selected to Last xml file selected in order to Front
'Copy and Paste TMG tab
Sheets("TMG_4 0").Activate
StartRow = 2
LastRow = Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastColumn = Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
LastCell = Cells(LastRow, LastColumn).Address 'Find lastcell of to be copied file
Range("A2:" & LastCell).Select
Selection.Copy
Windows("Allfiles(1).xml").Activate 'ERROR
Sheets("TMG_4 0").Activate
LastRow = Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastRow = LastRow + 1
Range("LastRow").Select 'ERROR
ActiveSheet.Paste
'Copy and Paste Gamma tab
Sheets("GammaCPS 0").Activate
StartRow = 2
LastRow = Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastColumn = Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
LastCell = Cells(LastRow, LastColumn).Address
Range("A2:" & LastCell).Select
Selection.Copy
Windows("Allfiles(1).xml").Activate 'ERROR Windows("File_name.xlsm").activate
Sheets("GammaCPS 0").Activate
LastRow = Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastRow = LastRow + 1
Range("LastRow").Select 'ERROR
ActiveSheet.Paste
test = test + 1
Loop
Windows("Allfiles(1).xml").Activate 'ERROR
ActiveWorkbook.SaveAs Filename:="C:\" & AllFiles(1) & AllFiles(test) & ".xlsm", FileFormat:=52
End Sub
You redim AllFiles but never fill it with anything. Is there missing code?
AllFiles is a 0 based array so if you want to start at the second element you need to use test = 1 instead of test = 2.
For looping through an array, try this:
For test = 1 to ubound(AllFiles) - 1 'This loops through the array from the second element to the last
Is "LastRow" a named range? If not, that's not going to work. The following will select the last used row in a worksheet:
activesheet.Rows(activesheet.usedrange.rows.count).select
Your SaveAs is failing because 1) AllFiles looks like it's never filled and 2) your save path as you wrote would be literally: C:\Allfile(1)&Allfiles(count)\.xlsm. You want:
ActiveWorkbook.SaveAs Filename:= "C:\" & AllFiles(1) & AllFiles(test) & ".xlsm"
EDIT After Code Update
You never initialize your count variable, add count = 0 to the beginning just to be safe.
GetOpenFilename does in fact return the full path. Once you have that path stored in a variable (such as AllFiles()) you can get just the filename portion with mid(AllFiles(test), instrrev(AllFiles(test), "\") + 1)
You don't need the ReDim AllFiles(count) prior to your main Do Loop. ReDim erases the contents of the array unless you use the Preserve keyword.
Change Workbooks(AllFiles(test)).Activate to Workbooks(Mid(AllFiles(test), InStrRev(AllFiles(test), "\") + 1)).Activate to strip the path information and leave just the filename.
Windows("Allfiles(1).xml").Activate won't work since your sending a literal string. You want WORKBOOKS(Mid(AllFiles(1), InStrRev(AllFiles(1), "\") + 1)).Activate here again.
LastRow = LastRow + 1 probably isn't what you meant. Try Set LastRow = LastRow.Offset(1, 0)
Change Range("LastRow").Select to LastRow.select
All instances of Windows( should be changed to Workbooks(

Resources