Cómo buscar directorios para buscar o enumerar archivos

Resumen

Al buscar archivos, a menudo es necesario buscar en los subdirectorios. Este artículo muestra dos métodos para buscar directorios y recuperar información de archivos de forma recursiva.

Más información

Aunque Visual Basic proporciona métodos para recuperar información acerca de archivos y directorios, también puede utilizar las funciones de la API de Windows para estas tareas. Mediante la API no es más rápido que los métodos integrados, pero los dos métodos funcionan de forma un poco diferente. Por lo tanto, este artículo muestra dos técnicas para recuperar esta información. Si prueba ambos métodos, intente utilizar la misma ruta inicial y la cadena de búsqueda. Obtendrá resultados similares.

Tenga en cuenta que los siguientes ejemplos no incluyen la interceptación de errores completo, pero el método 2 detectar un caso especial donde la función VB GetAttr() se produce un error en Pagefile.sys, que es el archivo de paginación de memoria virtual de Windows NT. Además, según la cadena de búsqueda, la versión de API enumera y cuenta los nombres de directorio predeterminada, donde la versión VB no. Tenga en cuenta que los siguientes ejemplos no incluyen la interceptación de errores completo, pero el método 2 detectar un caso especial donde la función VB GetAttr() se produce un error en Pagefile.sys, que es el archivo de paginación de memoria virtual de Windows NT. La única diferencia en los resultados entre estos dos métodos es que el código VB no devuelve el archivo crear fechas.

Método 1: Uso de la API de Windows

  1. Inicie un nuevo proyecto EXE estándar en Visual Basic. Se creará Form1 de forma predeterminada.
  2. Agregar un control CommandButton denominado Command1, cuatro cuadros de texto denominan Text1, Text2, Text3 y Text4 y un control ListBox a Form1.
  3. Agregue un módulo desde el menú de proyectos e inserte el siguiente:
       Declare Function FindFirstFile Lib "kernel32" Alias _   "FindFirstFileA" (ByVal lpFileName As String, lpFindFileData _
    As WIN32_FIND_DATA) As Long

    Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" _
    (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long

    Declare Function GetFileAttributes Lib "kernel32" Alias _
    "GetFileAttributesA" (ByVal lpFileName As String) As Long

    Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) _
    As Long

    Declare Function FileTimeToLocalFileTime Lib "kernel32" _
    (lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long

    Declare Function FileTimeToSystemTime Lib "kernel32" _
    (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long

    Public Const MAX_PATH = 260
    Public Const MAXDWORD = &HFFFF
    Public Const INVALID_HANDLE_VALUE = -1
    Public Const FILE_ATTRIBUTE_ARCHIVE = &H20
    Public Const FILE_ATTRIBUTE_DIRECTORY = &H10
    Public Const FILE_ATTRIBUTE_HIDDEN = &H2
    Public Const FILE_ATTRIBUTE_NORMAL = &H80
    Public Const FILE_ATTRIBUTE_READONLY = &H1
    Public Const FILE_ATTRIBUTE_SYSTEM = &H4
    Public Const FILE_ATTRIBUTE_TEMPORARY = &H100

    Type FILETIME
    dwLowDateTime As Long
    dwHighDateTime As Long
    End Type

    Type WIN32_FIND_DATA
    dwFileAttributes As Long
    ftCreationTime As FILETIME
    ftLastAccessTime As FILETIME
    ftLastWriteTime As FILETIME
    nFileSizeHigh As Long
    nFileSizeLow As Long
    dwReserved0 As Long
    dwReserved1 As Long
    cFileName As String * MAX_PATH
    cAlternate As String * 14
    End Type

    Type SYSTEMTIME
    wYear As Integer
    wMonth As Integer
    wDayOfWeek As Integer
    wDay As Integer
    wHour As Integer
    wMinute As Integer
    wSecond As Integer
    wMilliseconds As Integer
    End Type

    Public Function StripNulls(OriginalStr As String) As String
    If (InStr(OriginalStr, Chr(0)) > 0) Then
    OriginalStr = Left(OriginalStr, _
    InStr(OriginalStr, Chr(0)) - 1)
    End If
    StripNulls = OriginalStr
    End Function

  4. Copie el código siguiente en el módulo de Form1:
       Option Explicit
    Function FindFilesAPI(path As String, SearchStr As String, _
    FileCount As Integer, DirCount As Integer)
    Dim FileName As String ' Walking filename variable...
    Dim DirName As String ' SubDirectory Name
    Dim dirNames() As String ' Buffer for directory name entries
    Dim nDir As Integer ' Number of directories in this path
    Dim i As Integer ' For-loop counter...
    Dim hSearch As Long ' Search Handle
    Dim WFD As WIN32_FIND_DATA
    Dim Cont As Integer
    Dim FT As FILETIME
    Dim ST As SYSTEMTIME
    Dim DateCStr As String, DateMStr As String

    If Right(path, 1) <> "\" Then path = path & "\"
    ' Search for subdirectories.
    nDir = 0
    ReDim dirNames(nDir)
    Cont = True
    hSearch = FindFirstFile(path & "*", WFD)
    If hSearch <> INVALID_HANDLE_VALUE Then
    Do While Cont
    DirName = StripNulls(WFD.cFileName)
    ' Ignore the current and encompassing directories.
    If (DirName <> ".") And (DirName <> "..") Then
    ' Check for directory with bitwise comparison.
    If GetFileAttributes(path & DirName) And _
    FILE_ATTRIBUTE_DIRECTORY Then
    dirNames(nDir) = DirName
    DirCount = DirCount + 1
    nDir = nDir + 1
    ReDim Preserve dirNames(nDir)
    ' Uncomment the next line to list directories
    'List1.AddItem path & FileName
    End If
    End If
    Cont = FindNextFile(hSearch, WFD) ' Get next subdirectory.
    Loop
    Cont = FindClose(hSearch)
    End If

    ' Walk through this directory and sum file sizes.
    hSearch = FindFirstFile(path & SearchStr, WFD)
    Cont = True
    If hSearch <> INVALID_HANDLE_VALUE Then
    While Cont
    FileName = StripNulls(WFD.cFileName)
    If (FileName <> ".") And (FileName <> "..") And _
    ((GetFileAttributes(path & FileName) And _
    FILE_ATTRIBUTE_DIRECTORY) <> FILE_ATTRIBUTE_DIRECTORY) Then
    FindFilesAPI = FindFilesAPI + (WFD.nFileSizeHigh * _
    MAXDWORD) + WFD.nFileSizeLow
    FileCount = FileCount + 1
    ' To list files w/o dates, uncomment the next line
    ' and remove or Comment the lines down to End If
    'List1.AddItem path & FileName

    ' Include Creation date...
    FileTimeToLocalFileTime WFD.ftCreationTime, FT
    FileTimeToSystemTime FT, ST
    DateCStr = ST.wMonth & "/" & ST.wDay & "/" & ST.wYear & _
    " " & ST.wHour & ":" & ST.wMinute & ":" & ST.wSecond
    ' and Last Modified Date
    FileTimeToLocalFileTime WFD.ftLastWriteTime, FT
    FileTimeToSystemTime FT, ST
    DateMStr = ST.wMonth & "/" & ST.wDay & "/" & ST.wYear & _
    " " & ST.wHour & ":" & ST.wMinute & ":" & ST.wSecond
    List1.AddItem path & FileName & vbTab & _
    Format(DateCStr, "mm/dd/yyyy hh:nn:ss") _
    & vbTab & Format(DateMStr, "mm/dd/yyyy hh:nn:ss")
    End If
    Cont = FindNextFile(hSearch, WFD) ' Get next file
    Wend
    Cont = FindClose(hSearch)
    End If

    ' If there are sub-directories...
    If nDir > 0 Then
    ' Recursively walk into them...
    For i = 0 To nDir - 1
    FindFilesAPI = FindFilesAPI + FindFilesAPI(path & dirNames(i) _
    & "\", SearchStr, FileCount, DirCount)
    Next i
    End If
    End Function

    Private Sub Command1_Click()
    Dim SearchPath As String, FindStr As String
    Dim FileSize As Long
    Dim NumFiles As Integer, NumDirs As Integer

    Screen.MousePointer = vbHourglass
    List1.Clear
    SearchPath = Text1.Text
    FindStr = Text2.Text
    FileSize = FindFilesAPI(SearchPath, FindStr, NumFiles, NumDirs)
    Text3.Text = NumFiles & " Files found in " & NumDirs + 1 & _
    " Directories"
    Text4.Text = "Size of files found under " & SearchPath & " = " & _
    Format(FileSize, "#,###,###,##0") & " Bytes"
    Screen.MousePointer = vbDefault
    End Sub

  5. Ejecute el proyecto. Escriba una ruta de acceso inicial en Texto1, una cadena de búsqueda en Texto2 (como *. * o *.txt) y, a continuación, haga clic en Command1.
Verá una lista de los archivos se encuentra la presentación en el control ListBox con la fecha de creación y la última fecha de modificación, el número real de archivos encuentra muestra en Texto3, y el tamaño total de los archivos encontrados en el directorio de inicio aparece en Texto4.

Método 2: Utilizar las funciones integradas de Visual Basic

Estas instrucciones crear en el ejemplo descrito previo, pero también pueden utilizarse en un nuevo proyecto.


  1. Abrir el proyecto mediante los pasos descritos en Method1
  2. Agregue otro control CommandButton denominado Command2, dos cuadros de texto más denominan Texto5 y Texto6 y otro ListBox, Lista2 a Form1.
  3. Copie el código siguiente en el módulo de Form1:
       Function FindFiles(path As String, SearchStr As String, _       FileCount As Integer, DirCount As Integer)
    Dim FileName As String ' Walking filename variable.
    Dim DirName As String ' SubDirectory Name.
    Dim dirNames() As String ' Buffer for directory name entries.
    Dim nDir As Integer ' Number of directories in this path.
    Dim i As Integer ' For-loop counter.

    On Error GoTo sysFileERR
    If Right(path, 1) <> "\" Then path = path & "\"
    ' Search for subdirectories.
    nDir = 0
    ReDim dirNames(nDir)
    DirName = Dir(path, vbDirectory Or vbHidden Or vbArchive Or vbReadOnly _
    Or vbSystem) ' Even if hidden, and so on.
    Do While Len(DirName) > 0
    ' Ignore the current and encompassing directories.
    If (DirName <> ".") And (DirName <> "..") Then
    ' Check for directory with bitwise comparison.
    If GetAttr(path & DirName) And vbDirectory Then
    dirNames(nDir) = DirName
    DirCount = DirCount + 1
    nDir = nDir + 1
    ReDim Preserve dirNames(nDir)
    'List2.AddItem path & DirName ' Uncomment to list
    End If ' directories.
    sysFileERRCont:
    End If
    DirName = Dir() ' Get next subdirectory.
    Loop

    ' Search through this directory and sum file sizes.
    FileName = Dir(path & SearchStr, vbNormal Or vbHidden Or vbSystem _
    Or vbReadOnly Or vbArchive)
    While Len(FileName) <> 0
    FindFiles = FindFiles + FileLen(path & FileName)
    FileCount = FileCount + 1
    ' Load List box
    List2.AddItem path & FileName & vbTab & _
    FileDateTime(path & FileName) ' Include Modified Date
    FileName = Dir() ' Get next file.
    Wend

    ' If there are sub-directories..
    If nDir > 0 Then
    ' Recursively walk into them
    For i = 0 To nDir - 1
    FindFiles = FindFiles + FindFiles(path & dirNames(i) & "\", _
    SearchStr, FileCount, DirCount)
    Next i
    End If

    AbortFunction:
    Exit Function
    sysFileERR:
    If Right(DirName, 4) = ".sys" Then
    Resume sysFileERRCont ' Known issue with pagefile.sys
    Else
    MsgBox "Error: " & Err.Number & " - " & Err.Description, , _
    "Unexpected Error"
    Resume AbortFunction
    End If
    End Function

    Private Sub Command2_Click()
    Dim SearchPath As String, FindStr As String
    Dim FileSize As Long
    Dim NumFiles As Integer, NumDirs As Integer

    Screen.MousePointer = vbHourglass
    List2.Clear
    SearchPath = Text1.Text
    FindStr = Text2.Text
    FileSize = FindFiles(SearchPath, FindStr, NumFiles, NumDirs)
    Text5.Text = NumFiles & " Files found in " & NumDirs + 1 & _
    " Directories"
    Text6.Text = "Size of files found under " & SearchPath & " = " & _
    Format(FileSize, "#,###,###,##0") & " Bytes"
    Screen.MousePointer = vbDefault
    End Sub

    Private Sub Form_Load()
    Command1.Caption = "Use API code"
    Command2.Caption = "Use VB code"
    ' start with some reasonable defaults
    Text1.Text = "C:\My Documents\"
    Text2.Text = "*.*"
    End Sub

  4. Ejecute el proyecto. Escriba una ruta de acceso inicial en Texto1, una cadena de búsqueda en Texto2 (como *. * o Myfile?.txt etc.) y, a continuación, haga clic en Command2.
Aparece una lista de los archivos encontrados en Lista2 con la fecha de última modificación, el número de archivos encontrados en Texto5, y el tamaño total de los archivos que se encuentra bajo el directorio inicial en Texto6. Mediante la combinación de estos dos métodos en un formulario puede comprobar que ambos métodos devuelven información coincidente.


Método 3: Utilizar el objeto FileSystem con Visual Basic

Para obtener información acerca de cómo utilizar FileSystemObject con Visual Basic para buscar o lista de archivos, consulte el artículo siguiente en Microsoft Knowledge Base:
185601 cómo buscar de forma recursiva directorios utilizando FileSystemObject
Propiedades

Id. de artículo: 185476 - Última revisión: 01/09/2017 - Revisión: 1

Comentarios