Dirlisting - lister un dossier et ses sous dossiers tres rapidement

Contenu du snippet

Cette classe vous offre un moyen simple et rapide de lister le contenu d'un repertoire.
Elle est inspiree de la source de Renfield : http://www.vbfrance.com/code.aspx?ID=43640
J'aporte cependant les choses suivantes :
1) Prise en charge de tous les attributs geres par la fonction FindFirstFileW
2) Utilisable exactement comme la fonction Dir, bien que plus rapide comme l'avait deja souligne Renfield :
Dim dl as New DirListing
dl.Dir "C:\WINDOWS\system32\*", Not dlDirectory
Do: Debug.Print dl.Name
Loop while dl.Dir
3) Gestion precise et non equivoque du chemin d'acces. Toute recherche (sur un chemin relatif ou absolu) est converti en chemin absolu et sans equivoque.
4) La recherche est en plus recursive.

Source / Exemple :


'*********************************************************************************************************************'
'*********************************************************************************************************************'
'**                                                                                                                 **'
'**                                             DIRECTORY LISTING CLASS                                             **'
'**                                                                                                                 **'
'*********************************************************************************************************************'
'*********************************************************************************************************************'

'--------------------------------------------------   ATTRIBUTES   ---------------------------------------------------'
'Author:        Santiago Diez
'Email:         santiago.diez@caoba.fr
'Website:       http://santiago.diez.free.fr
'Date:          2008-05-06  07:28:20
'Version:       1.1.2
'Copyright:     None
'Description:   This class provides a powerfull and fast way to list files in a directory.
'Bugs:          No bug reported
'Sources:       Renfield's file listing Class (http://www.vbfrance.com/code.aspx?ID=43640)
'Requirements:  msvbvm60.dll, VB6.OLB, VB6FR.DLL (Always required)

'----------------------------------------------------   OPTIONS   ----------------------------------------------------'
Option Base 1
Option Compare Binary
Option Explicit

'---------------------------------------------------   CONSTANTS   ---------------------------------------------------'
Const SELF_DIRECTORY As String = "." & vbNullChar & vbNullChar
Const SELF_DIRECTORY_LEN As Long = 3
Const PARENT_DIRECTORY As String = "." & vbNullChar & "." & vbNullChar & vbNullChar
Const PARENT_DIRECTORY_LEN As Long = 5
Const MAXDEPTH As Long = 32

'------------------------------------------------   ENUMS AND TYPES   ------------------------------------------------'
'dlFileAttributes Constants
'   Constants used to enumerate file attributes.
'---------------------------------------------------------------------------------------------------------------------'
Enum dlFileAttributes
    dlReadOnly = 1
    dlHidden = 2
    dlSystem = 4
    'dlVolume = 8           'Not supported
    dlDirectory = 16
    dlArchive = 32
    'dlAlias = 64           'Not supported
    dlNormal = 128
    dlTemporary = 256
    dlSparseFile = 512
    dlReparsePoint = 1024
    dlCompressed = 2048
    dlOffline = 4096
    dlNotIndexed = 8192
    dlEncrypted = 16384
    dlRecursive = 32768     'Not applicable to file attribute. Just makes the search recursive
End Enum

'---------------------------------------------------------------------------------------------------------------------'
'SYSTEMTIME Data Type
'   Type used to represent date/time in the system.
'---------------------------------------------------------------------------------------------------------------------'
Private 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

'---------------------------------------------------------------------------------------------------------------------'
'FILETIME Data Type
'   Type used in WIN32_FIND_DATA Data Type.
'---------------------------------------------------------------------------------------------------------------------'
Private Type FILETIME
    dwLowDateTime       As Long
    dwHighDateTime      As Long
End Type

'---------------------------------------------------------------------------------------------------------------------'
'WIN32_FIND_DATA Data Type
'   Type used in declared function FindFirstFileW.
'---------------------------------------------------------------------------------------------------------------------'
Private 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 * 520
    cAlternate          As String * 28
End Type

'---------------------------------------------------------------------------------------------------------------------'
'Search Data Type
'   Type used to stack recursive searches.
'---------------------------------------------------------------------------------------------------------------------'
Private Type Search
    Handle      As Long
    Path        As String
End Type

'-----------------------------------------------   GLOBAL VARIABLES   ------------------------------------------------'
Dim SearchMask As String            'Search mask (eg. "*.cls")
Dim SearchAttributes As Long        'Search attributes
Dim SearchRecursive As Long         'Search in subfolders (zero or cdRecursive)
Dim Search() As Search              'Stack of recursive searches
Dim CurSearch As Long               'Position of the current search in the stack
Dim fileinfo As WIN32_FIND_DATA     'Description of a found file

'+-------------------------------------------------------------------------------------------------------------------+'
'+                                                      EVENTS                                                       +'
'+-------------------------------------------------------------------------------------------------------------------+'

'+-------------------------------------------------------------------------------------------------------------------+'
'+                                                 DECLARED FUNCTIONS                                                +'
'+-------------------------------------------------------------------------------------------------------------------+'
'FindFirstFileW Function
'   <Description>
'       Searches a directory for a file or subdirectory with a name that matches a specific name.
'   <Syntax>
'       FindFirstFileW(*pathname*, *fileinfo*)
'   <Parameters>
'       *pathname*  Required, Long Pointer  to a String. The  directory or path, and  the file name, which  can include
'                   wildcard characters, for example, an asterisk (*) or a question mark (?).
'       *fileinfo*  Required. A pointer to  the WIN32_FIND_DATA structure that receives information  about a found file
'                   or subdirectory.
'   <Returned value>
'       If the function  succeeds, the return value  is a search handle used  in a subsequent call  to FindNextFileW or
'       FindClose. If it fails, the return value is INVALID_HANDLE_VALUE (-1).
'---------------------------------------------------------------------------------------------------------------------'
Private Declare Function FindFirstFileW Lib "kernel32" (ByVal PathName As Long, fileinfo As WIN32_FIND_DATA) As Long

'---------------------------------------------------------------------------------------------------------------------'
'FindNextFile Function
'   <Description>
'       Continues a file search from a previous call to the FindFirstFileW function.
'   <Syntax>
'       FindNextFileW(*SearchHandle*, *fileinfo*)
'   <Parameters>
'       *SearchHandle*  Required, Long. The search handle returned by a previous call to the FindFirstFileW function.
'       *fileinfo*      Required. A pointer to the WIN32_FIND_DATA structure  that receives information about the found
'                       file or subdirectory.
'   <Returned value>
'       If the function succeeds, the return value is nonzero. If it fails, the return value is zero (0).
'---------------------------------------------------------------------------------------------------------------------'
Private Declare Function FindNextFileW Lib "kernel32" (ByVal SearchHandle As Long, fileinfo As WIN32_FIND_DATA) As Long

'---------------------------------------------------------------------------------------------------------------------'
'FindClose Function
'   <Description>
'       Closes a file search handle opened by the FindFirstFileW function.
'   <Syntax>
'       FindClose(*SearchHandle*)
'   <Parameters>
'       *SearchHandle*  Required, Long. The search handle returned by a previous call to the FindFirstFileW function.
'   <Returned value>
'       If the function succeeds, the return value is nonzero. If it fails, the return value is zero (0).
'---------------------------------------------------------------------------------------------------------------------'
Private Declare Function FindClose Lib "kernel32" (ByVal SearchHandle As Long) As Long

'---------------------------------------------------------------------------------------------------------------------'
'FileTimeToLocalFileTime Function
'   <Description>
'       Converts a file time to a local file time.
'   <Syntax>
'       FileTimeToLocalFileTime(*FileTime_*, *LocalFileTime_*)
'   <Parameters>
'       *FileTime_*         Required.  A pointer  to a  FILETIME structure  containing the  UTC-based file  time to  be
'                           converted into a local file time.
'       *LocalFileTime_*    Required. A pointer to a FILETIME structure to  receive the converted local file time. This
'                           parameter cannot be the same as the *FileTime_* parameter.
'   <Returned value>
'       If the function succeeds, the return value is nonzero. If it fails, the return value is zero.
'---------------------------------------------------------------------------------------------------------------------'
Private Declare Function FileTimeToLocalFileTime Lib "kernel32" (ByRef FileTime_ As FILETIME, ByRef LocalFileTime_ As _
FILETIME) As Long

'---------------------------------------------------------------------------------------------------------------------'
'FileTimeToSystemTime Function
'   <Description>
'       Converts a file time to system time format.
'   <Syntax>
'       FileTimeToSystemTime(*FileTime_*, *SystemTime_*)
'   <Parameters>
'       *FileTime_*     Required. A pointer to a FILETIME structure containing  the file time to convert to system date
'                       and time format.
'       *SystemTime_*   Required. A pointer to a SYSTEMTIME structure to receive the converted file time.
'   <Returned value>
'       If the function succeeds, the return value is nonzero. If it fails, the return value is zero.
'---------------------------------------------------------------------------------------------------------------------'
Private Declare Function FileTimeToSystemTime Lib "kernel32" (ByRef FileTime_ As FILETIME, ByRef SystemTime_ As _
SYSTEMTIME) As Long

'---------------------------------------------------------------------------------------------------------------------'
'RtlMoveMemory Method
'   <Description>
'       The RtlMoveMemory  routine moves memory  either forward or  backward, aligned  or unaligned, in  4-byte blocks,
'       followed by any remaining bytes.
'   <Syntax>
'       RtlMoveMemory *Destination*, *Source*, *Length*
'   <Parameters>
'       *Destination*   Required. Pointer to the destination of the move.
'       *Source*        Required. Pointer to the memory to be copied.
'       *Lenth*         Required. Specifies the number of bytes to be copied.
'---------------------------------------------------------------------------------------------------------------------'
Private Declare Sub RtlMoveMemory Lib "kernel32" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)

'+-------------------------------------------------------------------------------------------------------------------+'
'+                                                  ERROR HANDLING                                                   +'
'+-------------------------------------------------------------------------------------------------------------------+'
'ErrRaise Method
'   <Description>
'       Raises a class specific, user defined error.
'   <Syntax>
'       ErrRaise *number*
'   <Parameters>
'       *number*    Required, Long. Integer that  identifies the nature of the error. The  range 513-65535 is available
'                   for user-defined errors. Outside this range, a standard Visual Basic error is generated.
'---------------------------------------------------------------------------------------------------------------------'
Private Sub ErrRaise(number As Long)
    Const Source As String = "DirListing"
    Dim description As String
    Select Case number
        Case Is < 513, Is > 65535
            Err.Raise number
        Case 513
            description = "Incorrect number of arguments"
        Case 514
            description = "No more files"
        Case Else
            description = "Undescribed error"
    End Select
    Err.Raise vbObjectError + number, Source, description
End Sub

'+-------------------------------------------------------------------------------------------------------------------+'
'+                                                     FUNCTIONS                                                     +'
'+-------------------------------------------------------------------------------------------------------------------+'
'GetStrFromUnicode Function
'   <Description>
'       Transform a unicode null terminated string into a readable string.
'   <Syntax>
'       GetStrFromUnicode(*Str*)
'   <Parameters>
'       *Str*   Required. The unicode string that will b evaluated
'---------------------------------------------------------------------------------------------------------------------'
Private Function GetStrFromUnicode(Str As String) As String
    GetStrFromUnicode = StrConv(Left$(Str, InStr(Str, String$(2, 0))), vbFromUnicode)
End Function

'---------------------------------------------------------------------------------------------------------------------'
'SplitPathName Method
'   <Description>
'       Splits a path (relative or absolute) into two parts:  1) the absolute, fully qualified path without the name or
'       mask. 2) the name or mask.
'   <Syntax>
'       SplitPathName *PathName*, *Path*, *Mask*
'   <Parameters>
'       *PathName*  Required. Path specification to split.
'       *Path*      Required. A string variable in whitch the path will be stored.
'       *Mask*      Required. A string variable in whitch the mask will be stored.
'---------------------------------------------------------------------------------------------------------------------'
Private Sub SplitPathName(ByVal PathName As String, Path As String, Mask As String)
    Dim i As Long, fileparent As WIN32_FIND_DATA
    'Build absolute path
    If Left$(PathName, 2) = "\\" Then       'This is a UNC path, there is nothing to append
    ElseIf Left$(PathName, 1) = "\" Then    'This is a relative path from the root of the current drive
        PathName = Left$(CurDir$, 2) & PathName
    ElseIf InStr(PathName, ":") Then        'This is an absolute path, there is nothing to append
        'Change every ":" into ":\" because Dir("C:WINDOWS") is interpreted as Dir("C:\WINDOWS")
        'If there are other ":", it will anyway lead to no find items.
        'If there's already a ":\" it will become ":\\" which will anyway be interpreted as ":\"
        PathName = Replace(PathName, ":", ":\")
    Else                                    'This is a relative path from the current directory
        PathName = CurDir$ & "\" & PathName
    End If
    'Get mask and pathname's parent folder
    If Right$(PathName, 1) = "\" Then
        Mask = "*"
        PathName = PathName & "."
    ElseIf Right$(PathName, 2) = "\." Then
        Mask = "*"
        'PathName = PathName
    ElseIf Right$(PathName, 3) = "\.." Then
        Mask = "*"
        'PathName = PathName
    Else
        i = InStrRev(PathName, "\")
        If i Then
            Mask = Mid$(PathName, i + 1)
            PathName = Left$(PathName, i) & "."
        Else    'Cases like "C:" or "D:"
            Mask = "*"
            PathName = PathName & "\."
        End If
    End If
    'Built fully qualified path
    Path = ""
    Do While FindFirstFileW(StrPtr(PathName), fileparent) > 0
        Path = GetStrFromUnicode(fileparent.cFileName) & "\" & Path
        PathName = PathName & "\.."
    Loop
    'If path is still empty, PathName is either "C:\." or inexistant. So we check the existence:
    On Error GoTo ErrWrongPath
    If Path = "" Then GetAttr PathName
    'Append drive letter
    Path = Left$(PathName, 3) & Path
    '# needs further work to take into consideration UNC paths) #'
ErrWrongPath:
End Sub

'---------------------------------------------------------------------------------------------------------------------'
'FileTimeToDate Function
'   <Description>
'       Converts a File Time into a Date.
'   <Syntax>
'       FileTimeToDate(*FileTime_*)
'   <Parameters>
'       *FileTime_* Required. A pointer to a FILETIME structure containing  the file time to convert to a Date.
'---------------------------------------------------------------------------------------------------------------------'
Private Function FileTimeToDate(ByRef FileTime_ As FILETIME) As Date
    Dim LocalFileTime_ As FILETIME
    Dim SystemTime_ As SYSTEMTIME
    FileTimeToLocalFileTime FileTime_, LocalFileTime_
    FileTimeToSystemTime LocalFileTime_, SystemTime_
    With SystemTime_
        If .wMilliseconds >= 500 Then .wSecond = .wSecond + 1
        FileTimeToDate = DateSerial(.wYear, .wMonth, .wDay) + TimeSerial(.wHour, .wMinute, .wSecond)
    End With
End Function

'+-------------------------------------------------------------------------------------------------------------------+'
'+                                               BUILDER AND DESTROYER                                               +'
'+-------------------------------------------------------------------------------------------------------------------+'
Private Sub Class_Initialize()
    ReDim Search(MAXDEPTH)
End Sub
Private Sub Class_Terminate()
    Dim i As Long
    For i = 1 To CurSearch
        If Search(i).Handle Then FindClose Search(i).Handle
    Next
    CurSearch = 0
End Sub

'+-------------------------------------------------------------------------------------------------------------------+'
'+                                                    PROPERTIES                                                     +'
'+-------------------------------------------------------------------------------------------------------------------+'
'Name, FullPath, Extension Properties
'   <Description>
'       .......
'---------------------------------------------------------------------------------------------------------------------'
Property Get Name() As String
    If CurSearch Then Name = GetStrFromUnicode(fileinfo.cFileName)
End Property
Property Get RelPath() As String
    If CurSearch Then RelPath = GetStrFromUnicode(fileinfo.cFileName)
End Property
Property Get FullPath() As String
    If CurSearch Then FullPath = Search(CurSearch).Path & Name
End Property
Property Get Extension() As String
    Dim i As Long, j As Long, Str As String
    Str = fileinfo.cFileName
    If CurSearch And Not CBool(fileinfo.dwFileAttributes And dlDirectory) Then
        i = InStr(Str, vbNullChar & vbNullChar)
        j = InStrRev(Str, "." & vbNullChar, i)
        If j Then Extension = StrConv(Mid$(Str, j + 2, i - j - 1), vbFromUnicode)
    End If
End Property

'---------------------------------------------------------------------------------------------------------------------'
'---------------------------------------------------------------------------------------------------------------------'
Property Get Attributes() As Long
    If CurSearch Then Attributes = fileinfo.dwFileAttributes
End Property

'---------------------------------------------------------------------------------------------------------------------'
'---------------------------------------------------------------------------------------------------------------------'
Property Get DateCreated() As Date
    If CurSearch Then DateCreated = FileTimeToDate(fileinfo.ftCreationTime)
End Property

'---------------------------------------------------------------------------------------------------------------------'
'---------------------------------------------------------------------------------------------------------------------'
Property Get DateLastModified() As Date
    If CurSearch Then DateLastModified = FileTimeToDate(fileinfo.ftLastWriteTime)
End Property

'---------------------------------------------------------------------------------------------------------------------'
'---------------------------------------------------------------------------------------------------------------------'
Property Get DateLastAccessed() As Date
    If CurSearch Then DateLastAccessed = FileTimeToDate(fileinfo.ftLastAccessTime)
End Property

'---------------------------------------------------------------------------------------------------------------------'
'---------------------------------------------------------------------------------------------------------------------'
Property Get FileSize() As Currency
    Dim FileSize2(2) As Long
    'File bigger than 4 GB!!!
    If fileinfo.nFileSizeHigh Then
        'Get size as two longs
        FileSize2(1) = fileinfo.nFileSizeLow
        FileSize2(2) = fileinfo.nFileSizeHigh
        'Copy to a Currency
        RtlMoveMemory FileSize, FileSize2(1), 8
    Else
        'File smaller than 4 GB
        FileSize = fileinfo.nFileSizeLow
    End If
End Property
Property Get EOF() As Boolean
    EOF = CurSearch = 0
End Property

'+-------------------------------------------------------------------------------------------------------------------+'
'+                                                 SEARCH FUNCTIONS                                                  +'
'+-------------------------------------------------------------------------------------------------------------------+'
'MoveNext Method
'   <Description>
'       Moves to next file in search directory that matches attributes specifications.
'   <Syntax>
'       MoveNext
'   <Parameters>
'       None.
'---------------------------------------------------------------------------------------------------------------------'
Private Sub MoveNext()
    Dim Handle As Long, Found As Boolean, Flag As Boolean
    Do
        Handle = Search(CurSearch).Handle
        Do
            'Move to next found item...
            If Handle Then  '... continuing current search
                Found = FindNextFileW(Handle, fileinfo)
            Else            '... or starting a new search
                Handle = FindFirstFileW(StrPtr(Search(CurSearch).Path & SearchMask), fileinfo)
                Search(CurSearch).Handle = Handle
                Found = Handle > 0
            End If
        'Loops until the found item matches attributes specifications or there is no more items
        Loop Until (CBool(fileinfo.dwFileAttributes And (SearchAttributes Or SearchRecursive)) _
        And (Left$(fileinfo.cFileName, SELF_DIRECTORY_LEN) <> SELF_DIRECTORY) _
        And (Left$(fileinfo.cFileName, PARENT_DIRECTORY_LEN) <> PARENT_DIRECTORY)) _
        Or Not Found
        'If no more items, resume parent search
        If Not Found Then
            FindClose Search(CurSearch).Handle
            CurSearch = CurSearch - 1
            Flag = CurSearch = 0
        'If found item is a folder and recursive search is on, create a new search
        ElseIf (fileinfo.dwFileAttributes And SearchRecursive) Then
            CurSearch = CurSearch + 1
            Search(CurSearch).Handle = 0
            Search(CurSearch).Path = Search(CurSearch - 1).Path & Name & "\"
            Flag = fileinfo.dwFileAttributes And SearchAttributes
        Else
            Flag = True
        End If
    'Loops until the found item matches attributes specifications or there is no more search in progress
    Loop Until Flag
End Sub

'---------------------------------------------------------------------------------------------------------------------'
'.......
'   <Description>
'       .......
'   <Syntax>
'       Dir [*pathname*[, *attributes*]]
'   <Parameters>
'       .......
'---------------------------------------------------------------------------------------------------------------------'
Function Dir(Optional PathName, Optional Attributes As dlFileAttributes) As Boolean
    'If PathName is missing, continue current search
    If IsMissing(PathName) Then
        'You can't change attributes specification during a search
        If Attributes Then ErrRaise 513
        'Calling Dir after the last item returns False, calling Dir again raises an error
        If CurSearch = 0 Then ErrRaise 514
        'Move to next item
        MoveNext
    'Start new search
    Else
        'Stop current searches
        Class_Terminate
        'Save search parameters
        SplitPathName PathName, Search(1).Path, SearchMask
        If Search(1).Path = "" Then
            CurSearch = 0
        Else
            If Attributes = 0 Then SearchAttributes = &HFFFFFF Else SearchAttributes = Attributes
            If SearchAttributes And dlRecursive Then SearchRecursive = dlDirectory Else SearchRecursive = 0
            CurSearch = 1
            Search(1).Handle = 0
            'Move to next item
            MoveNext
        End If
    End If
    Dir = CurSearch
End Function

Conclusion :


Ceux qui ont deja vu mes sources reconnaitront ma sale habitude de tout commenter en anglais. J'ai appris a coder dans une boite americaine et je travaille avec des anglophones donc je peux difficilement faire autrement.
Bonne prog a tous.
Santiago

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.