Получить список файлов Excel в папке с помощью VBA

Мне нужно получить имена всех файлов Excel в папке, а затем внести изменения в каждый файл. Я получил часть "внести изменения". Есть ли способ получить список файлов .xlsx в одной папке, скажем D:\Personal и сохранить его в String Array.

Затем мне нужно перебирать список файлов и запускать макрос в каждом из файлов, которые, как я полагал, я могу сделать, используя:

Filepath = "D:\Personal\"
For Each i in FileArray
    Workbooks.Open(Filepath+i)
Next

Я просмотрел этот, однако мне не удалось открыть файлы, потому что он сохранил имена в формате Variant.

Короче говоря, как я могу использовать VBA для получения списка имен файлов Excel в определенной папке?

Ответ 1

Хорошо, это может сработать для вас, функция, которая берет путь и возвращает массив имен файлов в папке. Вы можете использовать оператор if, чтобы получить только файлы Excel при циклическом просмотре массива.

Function listfiles(ByVal sPath As String)

    Dim vaArray     As Variant
    Dim i           As Integer
    Dim oFile       As Object
    Dim oFSO        As Object
    Dim oFolder     As Object
    Dim oFiles      As Object

    Set oFSO = CreateObject("Scripting.FileSystemObject")
    Set oFolder = oFSO.GetFolder(sPath)
    Set oFiles = oFolder.Files

    If oFiles.Count = 0 Then Exit Function

    ReDim vaArray(1 To oFiles.Count)
    i = 1
    For Each oFile In oFiles
        vaArray(i) = oFile.Name
        i = i + 1
    Next

    listfiles = vaArray

End Function

Было бы неплохо, если бы мы могли просто получить доступ к файлам в объекте files по номеру индекса, но, похоже, это не работает в VBA по какой-либо причине (ошибка?).

Ответ 2

Вы можете использовать встроенную функцию Dir или FileSystemObject.

У каждого из них есть свои сильные и слабые стороны.

Функция Dir

Функция Dir - это встроенный, легкий метод для получения списка файлов. Преимущества его использования:

  • Легко использовать
  • Хорошая производительность (это быстро)
  • Поддержка подстановочных знаков

Хитрость заключается в том, чтобы понять разницу между вызовом с параметром или без него. Вот очень простой пример для демонстрации:

Public Sub ListFilesDir(ByVal sPath As String, Optional ByVal sFilter As String)

    Dim sFile As String

    If Right(sPath, 1) <> "\" Then
        sPath = sPath & "\"
    End If

    If sFilter = "" Then
        sFilter = "*.*"
    End If

    'call with path "initializes" the dir function and returns the first file name
    sFile = Dir(sPath & sFilter)

   'call it again until there are no more files
    Do Until sFile = ""

        Debug.Print sFile

        'subsequent calls without param return next file name
        sFile = Dir

    Loop

End Sub

Если вы измените какой-либо из файлов внутри цикла, вы получите непредсказуемые результаты. Лучше прочитать все имена в массив строк перед выполнением каких-либо операций с файлами. Вот пример, который основан на предыдущем. Это функция, которая возвращает строковый массив:

Public Function GetFilesDir(ByVal sPath As String, _
    Optional ByVal sFilter As String) As String()

    'dynamic array for names
    Dim aFileNames() As String
    ReDim aFileNames(0)

    Dim sFile As String
    Dim nCounter As Long

    If Right(sPath, 1) <> "\" Then
        sPath = sPath & "\"
    End If

    If sFilter = "" Then
        sFilter = "*.*"
    End If

    'call with path "initializes" the dir function and returns the first file
    sFile = Dir(sPath & sFilter)

    'call it until there is no filename returned
    Do While sFile <> ""

        'store the file name in the array
        aFileNames(nCounter) = sFile

        'subsequent calls without param return next file
        sFile = Dir

        'make sure your array is large enough for another
        nCounter = nCounter + 1
        If nCounter > UBound(aFileNames) Then
            'preserve the values and grow by reasonable amount for performance
            ReDim Preserve aFileNames(UBound(aFileNames) + 255)
        End If

    Loop

    'truncate the array to correct size
    If nCounter < UBound(aFileNames) Then
        ReDim Preserve aFileNames(0 To nCounter - 1)
    End If

    'return the array of file names
    GetFilesDir = aFileNames()

End Function

Объект файловой системы

Объект файловой системы - это библиотека для операций ввода-вывода, которая поддерживает объектную модель для работы с файлами. Плюсы для этого подхода:

  • Intellisense
  • Надежная объектная модель

Вы можете добавить ссылку на "Объектную модель хоста сценариев Windows" (или "Среду выполнения сценариев Windows") и объявить ваши объекты следующим образом:

Public Sub ListFilesFSO(ByVal sPath As String)

    Dim oFSO As FileSystemObject
    Dim oFolder As Folder
    Dim oFile As File

    Set oFSO = New FileSystemObject
    Set oFolder = oFSO.GetFolder(sPath)
    For Each oFile In oFolder.Files
        Debug.Print oFile.Name
    Next 'oFile

    Set oFile = Nothing
    Set oFolder = Nothing
    Set oFSO = Nothing

End Sub

Если вы не хотите intellisense, вы можете сделать так, не устанавливая ссылку:

Public Sub ListFilesFSO(ByVal sPath As String)

    Dim oFSO As Object
    Dim oFolder As Object
    Dim oFile As Object

    Set oFSO = CreateObject("Scripting.FileSystemObject")
    Set oFolder = oFSO.GetFolder(sPath)
    For Each oFile In oFolder.Files
        Debug.Print oFile.Name
    Next 'oFile

    Set oFile = Nothing
    Set oFolder = Nothing
    Set oFSO = Nothing

End Sub

Ответ 3

Dim iIndex as Integer
Dim ws As Excel.Worksheet
Dim wb      As Workbook
Dim strPath As String
Dim strFile As String

strPath = "D:\Personal\"
strFile = Dir(strPath & "*.xlsx")

Do While strFile <> ""
    Set wb = Workbooks.Open(Filename:=strPath & strFile)

    For iIndex = 1 To wb.Worksheets.count
        Set ws = wb.Worksheets(iIndex)

        'Do something here.

    Next iIndex

 strFile = Dir 'This moves the value of strFile to the next file.
Loop

Ответ 4

Если все, что вам нужно, это имя файла без расширения файла

Dim fileNamesCol As New Collection
Dim MyFile As Variant  'Strings and primitive data types aren't allowed with collection

filePath = "c:\file directory" + "\"
MyFile = Dir$(filePath & "*.xlsx")
Do While MyFile <> ""
    fileNamesCol.Add (Replace(MyFile, ".xlsx", ""))
    MyFile = Dir$
Loop

Для вывода на лист Excel

Dim myWs As Worksheet: Set myWs = Sheets("SheetNameToDisplayTo")
Dim ic As Integer: ic = 1

For Each MyFile In fileNamesCol
    myWs.Range("A" & ic).Value = fileNamesCol(ic)
    ic = ic + 1
Next MyFile

В основном на основе техники, подробно описанной здесь: https://wordmvp.com/FAQs/MacrosVBA/ReadFilesIntoArray.htm

Ответ 5

Что касается ответа с голосованием, он мне понравился, за исключением того, что если результирующий массив "listfiles" используется в формуле массива {CSE}, все значения списка выводятся в горизонтальной строке. Чтобы они вышли в вертикальном столбце, я просто сделал массив двухмерным следующим образом:

ReDim vaArray(1 To oFiles.Count, 0)
i = 1
For Each oFile In oFiles
    vaArray(i, 0) = oFile.Name
    i = i + 1
Next