Astuces de recherche...
Home
- Accueil & nouveautés
- Les newsgroups VB
- Téléchargements
- L'équipe
- Nous contacter
- Liens
Rubriques
- Toutes les questions
- Affichage & graphismes
- Algorithmique
- API
- Base de registre
- Bases de données
- Contrôles
- Date & heure
- Déploiement
- Divers
- Erreurs & problèmes
- Fichiers & dossiers
- Généralités
- Impression
- Internet & mails
- Math
- Multimédia
- Réseaux
- Structures de données
- Texte & strings
- VB .Net
- VB Script
- VBA
- Windows

Question 172

Comment filtrer les fichiers d'un répertoire ?

L'article Comment lister les fichiers d'un répertoire présentait de façon simplifiée l'utilisation de 2 méthodes pour faire une simple liste des fichiers d'un répertoire. Cependant, il arrive fréquemment qu'en plus d'une simple énumération "brute" de l'ensemble des fichiers d'un répertoire, on doit :

  • Filtrer le contenu d'un répertoire ou d'une arborescence de répertoires, en ne gardant que certains fichiers, sur base de leur extension, d'une partie du nom, etc.
  • Obtenir des informations étendues sur ces fichiers (date de création ou de modification, date du dernier accès, attributs particuliers, etc.)

Cet article présente plusieurs techniques et fonctions permettant de réaliser ces tâches.

Utilisation de Dir et de son argument Path

La fonction Dir de Visual Basic à la syntaxe générale suivante :

Dir(Path, [Attributs])

La fonction retourne une chaîne de caractères correspondant au premier fichier trouvé, s'il existe. Les appels suivants à Dir, sans paramètres, retournent successivement les fichiers correspondants aux critères fixés par Path et Attributs. Point important : l'argument Path supporte l'utilisation des caractères "jokers" (* et ?) permettant de rechercher une partie d'un nom. Le caractère "*" signifie "suivi par n'importe quelle suite de caractères", le caractère "?" signifiant "n'importe quelle lettre". Les exemples suivants montrent quelques usages possibles de Dir avec Path.

Exemple : Recherche des fichiers ayant l'extension .txt

    Dim szFilename As String
    Dim SzPath As String
    
    SzPath = "c:\temp"
    szFilename = Dir(SzPath & "\*.txt")

La fonction retournera les fichiers: hello.txt et world.txt, par exemple.

Exemple : Recherche des fichiers de la forme "ils commencent par 2 lettres, puis il y a un "_" puis la lettre "x" puis des caractères puis l'extension de la forme ".ba" suivi d'exactement un caractère

    Dim szFilename As String
    Dim SzPath As String
    
    SzPath = "c:\temp"
    szFilename = Dir(SzPath & "\??_x*.ba?")

La fonction retournera les fichiers: ab_xwxcvbn.ba8 et ab_xabcdefg.ba1, par exemple.

Exemple pratique : Suppression de tous les fichiers ".bak" d'un répertoire

    Dim szFilename As String
    Dim SzPath As String
    Dim nb_fic As Long
    
    SzPath = "c:\temp"
    
    szFilename = Dir(SzPath & "\*.bak")
    While szFilename <> ""
        ' Suppression du fichier
        Kill SzPath & "\" & szFilename
        nb_fic = nb_fic + 1
        ' fichier suivant
        szFilename = Dir
    Wend
    MsgBox nb_fic & " fichiers supprimés."

Ces exemples montrent bien la simplicité et la souplesse d'emploi de la fonction Dir pour réaliser un ensemble de tâches courantes. Il est possible de réaliser des filtrages plus élaborés et se servant en plus des attributs et en combinant l'utilisation de Dir à l'utilisation de GetAttr et FileDateTime.

Utilisation de Dir et de son argument Attributs

La fonction Dir retourne par défaut tous les fichiers "normaux", c'est-à-dire sans attributs particuliers tels que "Lecture seule", "Caché", "Système", etc. Elle ne retourne pas non plus les répertoires.

Avec l'argument optionnel attributs, il est facile de récupérer, en plus des fichiers normaux, les fichiers ayant un attribut particulier. Les attributs possibles sont les suivants (pour une description détaillée de ces valeurs, voir la documentation de Dir, dans la section "Aller plus loin") :

Constante Valeur
vbNormal 0
vbReadOnly 1
vbHidden 2
vbSystem 4
vbVolume 8
vbDirectory 16

On peut combiner l'utilisation de plusieurs attributs par un OR logique ou simplement par "+". Comme il a été dit, le fait de spécifier un ou plusieurs attributs permet de renvoyer les fichiers ayant ces attributs en plus des autres. Il faut donc filtrer après coup avec la fonction GetAttr et un AND logique.

Exemple : Affichage de tous les fichiers ayant l'attribut "fichier caché"

    Dim szFilename As String
    Dim SzPath As String
    Dim fullName As String
    
    SzPath = "c:\temp"
    ' spécifie l'attribut vbHidden (fichier caché)
    szFilename = Dir(SzPath & "\*.*", vbHidden)
    While szFilename <> ""
        fullName = SzPath & "\" & szFilename
        ' avec GetAttr, on ne garde que les fichiers cachés
        If (GetAttr(fullName) And vbHidden) = vbHidden Then
            MsgBox "le fichier " & fullName & " est caché."
        End If
        szFilename = Dir()
    Wend

Exemple : Affichage de tous les sous-répertoires, sauf "." et ".."

    Dim szFilename As String
    Dim SzPath As String
    Dim fullName As String
    
    SzPath = "c:\temp"
    
    szFilename = Dir(SzPath & "\*.*", vbDirectory)
    While szFilename <> ""
        fullName = SzPath & "\" & szFilename
        ' garde les répertoires, sauf . et ..
        If (GetAttr(fullName) And vbDirectory) = vbDirectory Then
            If szFilename = "." Or szFilename = ".." Then
                ' on ne fait rien
            Else
                Debug.Print "Sous répertoire : " & szFilename
            End If
        End If
        szFilename = Dir()
    Wend

On peut aussi utiliser des fonctions telles que FileDateTime ou FileLen pour obtenir des informations supplémentaires sur le fichier et éventuellement affiner le résultat de la recherche.

Exemple : Affichage de tous les fichiers, y compris cachés et en lecture seule, avec affichage de la date et heure de création ou de modification

    Dim szFilename As String
    Dim SzPath As String
    Dim fullName As String
    Dim fic_dattime As Date
    
    SzPath = "c:\temp"
    szFilename = Dir(SzPath & "\*.*", vbReadOnly Or vbHidden)
    
    While szFilename <> ""
        fullName = SzPath & "\" & szFilename
        fic_dattime = FileDateTime(fullName)
        Debug.Print szFilename & vbTab & fic_dattime
        szFilename = Dir()
    Wend

Les exemples précédents couvrent en grande partie tout ce que l'on peut faire avec les fonctions Dir, GetAttr et FileDateTime. Ces techniques sont efficaces et suffisantes dans la plupart des cas. Comme on l'a dit dans l'article connexe Comment lister les fichiers d'un répertoire, la principale limitation à l'utilisation de Dir est que celle-ci n'est pas réentrante; elle ne permet donc pas une utilisation récursive, qui permettrait par exemple de lister récursivement une arborescence de répertoires et de sous-répertoires.

Utilisation avancées des API FindFirstFile et FindNextFile - La structure WIN32_FIND_DATA

L'article Comment lister les fichiers d'un répertoire présentait l'utilisation simplifiée des API, pour un simple listing des fichiers d'un répertoire. Cet article présente une utilisation plus avancée, en décrivant notamment les détails de la structure WIN32_FIND_DATA.

Il y a 2 intérêts principaux à l'utilisation des API FindFirstFile et FindNextFile :

  • Ces API retournent le fichier trouvé sous la forme d'une structure WIN32_FIND_DATA, contrairement à Dir() qui retourne uniquement un nom de fichier. La structure WIN32_FIND_DATA contient de nombreuses informations additionnelles sur le fichier, telles que la date de création, la date de dernier accès, la date de dernière modification, la taille, les attributs (plus détaillés que ceux de Dir) et même le nom alternatif (le nom "court", sous la forme 8+3).
  • Ces API sont réentrantes, elles peuvent être appelées de façon récursive. Ainsi, elles sont bien adaptées pour par exemple lister une arborescence de répertoires et de sous-répertoires.

En terme de filtrage sur le nom, l'API FindFirstFile à la même souplesse que Dir, permettant notamment d'utiliser les caractères "jokers" (* et ?) dans la construction du nom de fichier.

Exemple pratique : Liste de tous les fichiers d'un répertoire, affichage des membres de la structure WIN32_FIND_DATA

Option Explicit

' Déclaration des constantes
Private Const MAX_PATH = 260
Private Const INVALID_HANDLE_VALUE = -1
'
Private Const FILE_ATTRIBUTE_READONLY = &H1
Private Const FILE_ATTRIBUTE_HIDDEN = &H2
Private Const FILE_ATTRIBUTE_SYSTEM = &H4
Private Const FILE_ATTRIBUTE_DIRECTORY = &H10
Private Const FILE_ATTRIBUTE_ARCHIVE = &H20
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_ATTRIBUTE_TEMPORARY = &H100
Private Const FILE_ATTRIBUTE_COMPRESSED = &H800

' Déclaration des API
Private Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileA" _
       (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" _
       (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long

' Déclaration des Types
Private Type FILETIME
    dwLowDateTime As Long
    dwHighDateTime As Long
End Type

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 * MAX_PATH
    cAlternate As String * 14
End Type

Private Function ListDirectory(Path As String) As Boolean
    Dim lpFindFileData As WIN32_FIND_DATA
    Dim hFindFile As Long
    Dim fileName As String
    Dim shortFileName As String
    Dim fileSize As Currency ' allow size >4 GB
    Dim szAttr As String
    Dim attr As Long
    
    ListDirectory = False
    lpFindFileData.cAlternate = String$(14, 0)
    lpFindFileData.cFileName = String$(MAX_PATH, 0)

    hFindFile = FindFirstFile(Path, lpFindFileData)
    If hFindFile <> INVALID_HANDLE_VALUE Then
        Do
            fileName = Mid$(lpFindFileData.cFileName, 1, InStr(lpFindFileData.cFileName, Chr$(0)) - 1)
            Debug.Print "Nom long : " & fileName
            
            shortFileName = Mid$(lpFindFileData.cAlternate, 1, InStr(lpFindFileData.cAlternate, Chr$(0)) - 1)
            Debug.Print "Nom court : " & shortFileName
            
            fileSize = lpFindFileData.nFileSizeHigh * 2 ^ 32 + lpFindFileData.nFileSizeLow
            Debug.Print "Taille : " & fileSize
            
            szAttr = ""
            attr = lpFindFileData.dwFileAttributes
            If (attr And FILE_ATTRIBUTE_ARCHIVE) = FILE_ATTRIBUTE_ARCHIVE Then
                szAttr = szAttr & "A"
            End If
            If (attr And FILE_ATTRIBUTE_READONLY) = FILE_ATTRIBUTE_READONLY Then
                szAttr = szAttr & "R"
            End If
            If (attr And FILE_ATTRIBUTE_HIDDEN) = FILE_ATTRIBUTE_HIDDEN Then
                szAttr = szAttr & "H"
            End If
            If (attr And FILE_ATTRIBUTE_SYSTEM) = FILE_ATTRIBUTE_SYSTEM Then
                szAttr = szAttr & "S"
            End If
            If (attr And FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY Then
                szAttr = szAttr & "D"
            End If
            Debug.Print "Attributs : " & szAttr
            
            ' Les différentes dates :
            ' lpFindFileData.ftCreationTime
            ' lpFindFileData.ftLastAccessTime
            ' lpFindFileData.ftLastWriteTime
            
            lpFindFileData.cAlternate = String$(14, 0)
            lpFindFileData.cFileName = String$(MAX_PATH, 0)
        Loop Until FindNextFile(hFindFile, lpFindFileData) = 0
        ListDirectory = True
    End If
    FindClose hFindFile
End Function

Private Sub Command1_Click()

    Call ListDirectory("c:/temp/*.*")
End Sub

Note : Pour l'affichage et la récupération des dates, on se référera à l'article Comment déterminer la date de création, modification, ou de dernier accès d'un fichier ? qui présente de façon claire et détaillée les API telles que FileTimeToSystemTime qui permettent de transformer une date de type FILETIME en date au format VB.

Pour aller plus loin

Voir aussi :

Date de publication : 13 septembre 2007
Dernière modification : 06 mars 2008
Rubriques : Fichiers & dossiers
Mots-clés : lister, filtrer, Dir, fichiers, dossiers, wildcards, jokers, attributs, FindFirstFile, FindNextFile, GetAttr, FileDateTime, WIN32_FIND_DATA, FILETIME