'VBA: Remove objects from object collection

I want an Access application to autimatically import the right files from a certain folder. My idea to do this, is to get all files in the folder and then proceed with removing the wrong files from the collection. At the end, I start the import.

The problem is the removing part, VBA doesn't know the remove method in this context.

Here is an exemplary code:

Dim objFS As Object
Dim objFolder As Object
Dim objFiles As Object
Dim objF1 As Object

Set objFS = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFS.GetFolder(strPath)
Set objFiles = objFolder.Files

' remove files with wrong YearMonth from collection
For Each objF1 In objFiles
    If Left(Right(objF1.Name, 8), 6) <> YearMonth Then
        ' the following line causes the error
        objFiles.Remove (objF1.Name) 
    End If
Next

Is there no option to simply remove an object from objFiles?

If not, I guess I would just populate another array, store all objF1 I want to remove and us the array as an exclude-filter for the actual file import.

edit: Seems like I have to go with the array solution. Thanks for the help.

edit2: I went for a string array, stores all names of files I don´t want to import. Final import method checks for names in this list.

vba


Solution 1:[1]

This question is mega-old so I'm just answering this for posterity.

So, the reason one might not want to go the arraylist route is because GetFolder returns a collection of type File (class). The File class can do lots of cool things and we might want to hold on to that functionality. This example uses early binding, however the principals are the same and it can be applied to either case.

   Dim oFSO As Scripting.FileSystemObject
   Dim oFolder As Scripting.Folder
   Dim oFiles As Scripting.Files
   Dim oFile As Scripting.File
   Dim oFileNameList As Collection

   Set oFSO = New Scripting.FileSystemObject
   Set oFolder = oFSO.GetFolder("C:\YourDirectoryHere")
   Set oFiles = oFolder.Files
   For Each oFile In oFiles
       'This is what I'm using to filter out the specific file types i'm looking for.  
       'This can be whatever criterion you want to use.  Either way, what you're doing
       'is creating your own collection of Scripting.File objects.  You could also
       'exclude the filtering part here and just add them all directly to the collection
       'so that you can do what you need to at a later part of the code.
       If UCase(oFSO.GetExtensionName(oFile.Name)) = "XLSX" Then oFileNameList.Add oFile  
   Next oFile

At this point, oFileNameList is a Collection of multiple Scripting.File objects which is essentially what Scripting.Files is anyway. However the main difference is that you can add/remove files from this collection as needed. The individual objects in this collection can still be accessed individually as their original type. So you could still do something like oFileNameList.Item(1).Attributes = ReadOnly if you wanted to. Or, if using a For Each loop, oFile.Attributes = ReadOnly.

Keeping the functionality of Scripting.File objects can be useful and necessary depending on what you're doing. It can also be kinda dangerous if you're not paying attention.

Solution 2:[2]

The GetFolder methode returns an instance of FileCollection. According the docs, there is no way to remove objects from this collection. You might want to consider GetFolder as a solely informational method.

So if you want to stick to your remove-the-processed-files approach, you will have to make a copy to a mutable VBA.Collection upfront and work with that.

Solution 3:[3]

You can't modify collection if You work on this collection. You can make new list where You can add good files. For example:

List<int> listOfNumbers = new List<int>();

        for (int i = 0; i < 11; i++)
        {
            listOfNumbers.Add(i);
        }

        //The above collection includes 0-10 number but You need only even numbers

        //Your current option - not work because You can't modify collection used in foreach
        foreach (var item in listOfNumbers)
        {
            if (item % 2 == 1)
                listOfNumbers.Remove(item);
        }

        //Correct solution
        List<int> evenNumbers = new List<int>();
        foreach (var item in listOfNumbers)
        {
            if (item % 2 == 0)
                evenNumbers.Add(item);
        }

Solution 4:[4]

What about an ArrayList?

Sub SO()

strPath$ = "C:\Users\olearysa\desktop\"
MonthYear$ = "DateFi"

With CreateObject("System.Collections.ArrayList")

    fileName = Dir(strPath & "*.*", vbNormal)

    While Not fileName = vbNullString
        If Len(fileName) > 12 Then
            If Mid(fileName, InStrRev(fileName, ".") - 8, 6) = MonthYear Then .Add strPath & fileName
        End If
    fileName = Dir()
Wend

Debug.Print .count

For i = 0 To .count - 1
    '// Example
    Workbooks.Open .Item(i)
    '// more code here...
Next i

.Clear

End With

End Sub

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rudiez
Solution 2 paulroho
Solution 3 artur.z
Solution 4 SierraOscar