Comment lister les fichiers d'un répertoire ?
IntroductionIl est souvent utile de récupérer la liste des fichiers d'un répertoire. On peut le faire de différentes manières. Cet article présente 2 façons efficaces de le faire. La première méthode est pure VB, elle utilise la fonction Dir. La seconde est un rien plus compliquée, elle utilise les API FindFirstFile et FindNextFile. Cet article présente l'utilisation de Dir et des API FindFirstFile/FindNextFile, en se limitant volontairement à la simple énumération des fichiers d'un répertoire. Ces 2 méthodes permettent de faire beaucoup plus de choses, telles que filtrer les fichiers en fonction de leurs noms ou attributs, de récupérer des informations comme la taille, la dernière date d'accès, la date de création, etc. Tout ceci est expliqué en détails dans l'article complémentaire de celui-ci : Comment filtrer les fichiers d'un répertoire ?. Utilisation simplifiée de la fonction DirLa fonction Dir permet de récupérer les noms des fichiers d'un répertoire. Le premier appel à Dir se fait en précisant en paramètre le chemin de recherche. Il retourne le nom du premier fichier trouvé. Les appels successifs à Dir se font sans arguments. Ils renvoient alors les noms des fichiers suivants. Quand il n'y a pas ou plus de fichiers, la fonction retourne une chaîne vide. Note : on trouve parfois écrit "Dir$". Cette forme est équivalente à Dir. ExempleLe code suivant retourne les noms de tous les fichiers du répertoire "c:\temp". Il retourne les fichiers en lecture seule ("read-only"), mais pas les fichiers cachés ni les sous-répertoires : Dim FileName As String Dim Path As String Dim Filter As String
Path = "c:\temp\*.*"
FileName = Dir(Path) While FileName <> "" Debug.Print FileName FileName = Dir Wend
Une importante limitation de la fonction Dir est qu'elle n'est pas réentrante : cela signifie que l'on ne peut pas faire un appel à Dir au sein d'un autre appel à Dir. Ainsi, il n'est pas possible d'écrire une fonction récursive permettant de lister les fichiers des sous répertoires avec Dir. La suite de cet article montre comment on peut le faire avec les API. Utilisation des API FindFirstFile et FindNextFileLa fonction FindFirstFile permet de retrouver le premier fichier d'un répertoire. Pour retrouver les fichiers suivants du même répertoire, on appelle FindNextFile. Le principal avantage de ces fonctions est qu'elles retournent plus d'informations que Dir. Ceci est expliqué en détails dans l'article Comment filtrer les fichiers d'un répertoire? Les API FindFirstFile et FindNextFile ont aussi la propriété d'être réentrantres. On peut donc les utiliser au sein d'une fonction récursive pour lister une arborescence de répertoires et de sous-répertoires. Contrairement à l'idée reçue, l'usage de FindFirstFile et FindNextFile n'est pas (tellement) plus rapide en VB que l'utilisation de Dir. Cela est dû au fait que ces API retournent une chaîne "null terminated" (terminée par un zéro binaire), ce qui oblige à une manipulation assez coûteuse pour la remettre au format VB. Ceci dit, cette méthode garde un léger avantage en terme de performances, qui ne sera réellement visible que lors de l'exploration de répertoires contenant de très nombreux fichiers. ExempleLe code suivant fait la même chose que l'exemple précédent : Option Explicit
Private Const MAX_PATH = 260 Private Const INVALID_HANDLE_VALUE = -1
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 ListDirectory = False
hFindFile = FindFirstFile(Path, lpFindFileData) If hFindFile <> INVALID_HANDLE_VALUE Then Do fileName = Mid$(lpFindFileData.cFileName, 1, InStr(lpFindFileData.cFileName, Chr$(0)) - 1) Debug.Print fileName Loop Until FindNextFile(hFindFile, lpFindFileData) = 0 ListDirectory = True End If FindClose hFindFile End Function
Private Sub Command1_Click()
Call ListDirectory("c:/tempo/*.*") End Sub
RemarquesOn peut également faire ce type de tâches avec FSO. Cependant, l'usage de FSO a beaucoup d'inconvénients comme on peut le voir dans l'article suivant de la FAQ : Quels sont les désavantages du FSO (File System Object) ? Pour aller plus loin Voir aussi : |