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 PathLa 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 <> "" Kill SzPath & "\" & szFilename nb_fic = nb_fic + 1 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 AttributsLa 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" szFilename = Dir(SzPath & "\*.*", vbHidden) While szFilename <> "" fullName = SzPath & "\" & szFilename 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 If (GetAttr(fullName) And vbDirectory) = vbDirectory Then If szFilename = "." Or szFilename = ".." Then 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_DATAL'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_DATAOption Explicit
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
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
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 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 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 : |